I found a lot of tutorials showing how to start developing Android Applications using NDK.
But I have a rather "easy/stupid" question:
Please consider the following two tutorials:
http://mobile.tutsplus.com/tutorials/android/ndk-tutorial/
http://www.indiedb.com/tutorials/creating-compiling-and-deploying-native-projects-from-the-android-ndk
http://mindtherobot.com/blog/452/android-beginners-ndk-setup-step-by-step/
http://marakana.com/forums/android/examples/49.html
Now, in the second tutorial they are building the hello-jni example.
My question is:
After using the ndk-build
and producting the:
is it possible to use the resulted libhello-jni.so and distribute this to others instead of the actual C code?
For example modifying the Android.mk and replacing com_myproject_MyActivity.c to something.so in order to include the shared library?:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mylib
LOCAL_SRC_FILES := com_myproject_MyActivity.c
include $(BUILD_SHARED_LIBRARY)
Any suggestions or tutorials welcome. Thanks in advance.
You can use a prebuilt NDK library by copying it into libs/armeabi (or whatever architecture is it for), then loading in run-time. From the standpoint of the Android build system, it's just another file to include in the APK.
The problem, however, is that the JNI function names include, by convention, the name of the package and class they will belong to; so from the standpoint of a SO consumer project, its use will look rather unnatural, as none of the JNI functions would fit into its classes. You'll probably have to ship a companion JAR where the respective Java classes are declared.
Via VitamioBundle,
You no need to do re-using code:
is it possible to use the resulted libhello-jni.so and distribute this to others instead of the actual C code? For example modifying the Android.mk and replacing com_myproject_MyActivity.c to something.so in order to include the shared library?
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mylib
LOCAL_SRC_FILES := com_myproject_MyActivity.c
include $(BUILD_SHARED_LIBRARY)
VitamioBundle can be considered as shared library,
Therefore, you can use it as your Android Library.
Let's fun.
Related
I am new to Android development and I have no idea how to include the library that comes with the Google Tango SDK.
The app, as it is, is a small java wrapper around a c++ core that is basically a lightweight render engine. It can render one model and handle input. It is all done in C++ using Android NDK.
The problem is that I now want to use functions like onXyzIjAvailable(). How do I include and use the library? I know of this, but I need to include the library and get access to the TangoService_connectOnXYZijAvailable() function.
I want to stress that I am new to android development and I have never included anything. I have only written the code myself or used Android Studio to download and include the SDKs, generate the GRADLE files and take care of the compilation/makefles. I found this SO post talking about adding a library, but I did not understand the answer. How do I import it to this project and build it?
Thank you so much for the help.
You must download the current tango api and service sdk for C here
Unzip and place the folders (I named them tango_client_api and tango_service_sdk) you want to. I prefer a structure like that:
ProjectFolder/app/
ProjectFolder/build/...
...
tango_client_api/
tango_service_sdk/
third-party/...
...
Now you have to include the lib paths into your Android.mk makefile (located in path like ProjectFolder/app/src/main/jni/Android.mk) as followed:
LOCAL_PATH := $(call my-dir)
PROJECT_ROOT_FROM_JNI:= ../../../../..
PROJECT_ROOT:= $(call my-dir)/../../../../..
include $(CLEAR_VARS)
LOCAL_MODULE := lib_your_project_name
LOCAL_SHARED_LIBRARIES := tango_client_api
LOCAL_CFLAGS := -std=c++11
LOCAL_C_INCLUDES := $(PROJECT_ROOT)/tango_service_sdk/include/ \
LOCAL_SRC_FILES := your-project-file1.cc \
your-project-file2.cc \
your-project-file3.cc
LOCAL_LDLIBS := -llog -lGLESv2 -L$(SYSROOT)/usr/lib
include $(BUILD_SHARED_LIBRARY)
$(call import-add-path, $(PROJECT_ROOT))
$(call import-module,tango_client_api)
In your .h files you can use for example: #include <tango_client_api.h>
to get access to all TangoService_functions
And that's it. I really recommend you to look into the tango C examples on github https://github.com/googlesamples/tango-examples-c
I am trying to include my prebuilt library on the existing Android Module art/runtime/. I have followed the official documentation, found here. In detail, these are the changes I 've made:
Added lines in art/Android.mk:
# This makes sure my library's .mk is found
include $(art_path)/mylib/Android.mk
Added lines in art/runtime/Android.mk:
# Added this, after the LOCAL_C_INCLUDES
LOCAL_STATIC_LIBRARIES := mylib-prebuilt
# Also, on the next mention of LOCAL_STATIC_LIBRARIES, I changed the
# assignment operator to '+=', so mylib won't overriden
Include in art/runtime.cc source mylib's header:
#include "mylib.h"
// then at some point use it
I have put mylib sources in art/mylib. I manually build, using a regular Makefile, the archive libmylib.a, which I want to be statically linked to libart.so.
In the Android.mk found at art/mylib I have added the following:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mylib-prebuilt
LOCAL_SRC_FILES := $(LOCAL_PATH)/libmylib.a
LOCAL_EXPORT_C_INCLUDES := \
$(LOCAL_PATH)/mylib.h \
$(LOCAL_PATH)/another_header.h
include $(PREBUILT_STATIC_LIBRARY)
By exporting the C includes, the dependent modules should have automatically appended them to their local list. However, this is not the case, as I get the error:
fatal error: 'mylib.h' file not found
If I workaround this issue, with a stupid way that I really shouldn't, I stumble upon a link error, as my libmylib.a is never used during linking.
Other information:
I have placed mylib in art/mylib as it will be part of the art namespace and its methods will be calling/being called by art/runtime sources, e.g. runtime.cc. I have chosen to go with prebuilt-libraries, instead of directly including my sources, like Garbage Collector (found at art/runtime/gc`), as I want to pass particular compilation flags to individual source files.
I have already tried, and failed, solutions to other questions, found here and here.
Any thoughts?
EDIT:
When I try to make a full build, I get the following error:
make: *** No rule to make target
'out/host//obj/STATIC_LIBRARIES/mylib-prebuilt_intermediates/export_includes',
needed by
'out/host//obj/EXECUTABLES/dex2oat_intermediates/import_includes'.
Stop.
Thanks!
I finally managed to get this to work.
My library is now placed at art/runtime/mylib.
In art/runtime/Android.mk, I include the sources with:
LOCAL_C_INCLUDES += art/runtime/mylib
This makes mylib.h visible to the runtime source files.
The art/runtime/mylib/Android.mk has changed almost completely to:
LOCAL_MODULE := libmylib
LOCAL_SRC_FILES := libmylib.a
LOCAL_MODULE_SUFFIX := .a
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
include $(BUILD_PREBUILT)
In my previous attempts, LOCAL_EXPORT_C_INCLUDES, in contrary to documentation, it didn't copy files to the dependent modules. Also PREBUILT_STATIC_LIBRARY didn't seem to be working.
Now, I can build my library in an archive of objects, using regular makefiles, and the build system copies it each time it gets changed to the appropriate locations, so at the link stage can be blended with libart.so.
I have a series of existing libraries which I need to re-use in an Android application. The layout is similar to:
\Libraries\libOne
\Libraries\libTwo [Static library]
\Libraries\libThree
\Applications\MyApplication\ [Application]
libTwo depends on libOne, and libThree depends on libTwo. How can I get the build system to build all of the libraries in the correct order? I'm trying to use Eclipse, but if necessary I can use the command line.
All of these libraries will eventually be referenced by a Java application (and use JNI to interact with them). Any clues on how I setup the Android.mk / Application.mk files?
I've tried using BUILD_STATIC_LIBRARY for libTwo, but it doesn't actually output any files! I was expecting a libTwo.a file, but nothing gets compiled or built.
Do I write one Android.mk in the application? Or an Android.mk for each project?
OK, now I see your edit, and this makes it possible to answer the specific question.
You must have at least one Android.mk file for your application if you want to use Android NDK to build your native library/ies. This is not a requirement, though. It is OK to build it though Cmake, or a "standalone toolchain" with "traditional" makefiles, or with a MS Visual Studio plugin, or any other way. It is the result that matters. The result is a shared object built with a compatible compiler for a bionic runtime.
It makes goode sense to put the library in ${project_root}/libs/armeabi/ directory (for ARM v6 compatible devices, other subdirectories for x86, MIPS, arm v7a) to allow the APK builder pack it correctly, to allow app installer to unpack the correct version (compatible with the device processor) into /data/data/${package_name}/lib directory on the device, and finally to be able to use System.loadLibrary(short_name) to use it from Java. But it is also quite possible to pack the so file differently, unpack it manually, and load it from any place on the device file system (provided your app has permission to write and read this file).
But if we filter out exotic cases, it is much more comfortable to have an Android.mk in the ${project_root}/jni directory. In terms of ndk-build command, each library is a separate MODULE, but all three may be defined in one Android.mk file. On the other hand, if your libraries are isolated (e.g. come from separate 3rd parties), you will probably prefer to create three Android.mk files. Luckily, ndk-build is nothing but a wrapper around gnu make, and the simple include statement in Android.mk works as in any other makefiles.
In summary, your case is probably covered by a simple Applications/MyApplication/ [Application]/jni/Android.mk file:
include ../../Libraries/libOne/Android.mk
include ../../Libraries/libTwo/Android.mk
include ../../Libraries/libThree/Android.mk
I don't know what dependency you have between libOne and libTwo, but for libOne the file Libraries/libOne/Android.mk will look like
LOCAL_PATH = $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libOne
LOCAL_SRC_FILES := first.c
include $(BUILD_STATIC_LIBRARY)
and Libraries/libThree/Android.mk
LOCAL_PATH = $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libThree
LOCAL_SRC_FILES := third.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../libOne $(LOCAL_PATH)/../libTwo
LOCAL_STATIC_LIBRARIES := libOne libTwo
include $(BUILD_SHARED_LIBRARY)
You should run ndk-build from Applications/MyApplication/ [Application] directory - either from command prompt, or through Eclipse ADT plugin.
update the same may be expressed by one Android.mk file in jni directory:
LOCAL_PATH = ../../Libraries/libOne
include $(CLEAR_VARS)
LOCAL_MODULE := libOne
LOCAL_SRC_FILES := first.c
include $(BUILD_STATIC_LIBRARY)
LOCAL_PATH = ../../Libraries/libThree
include $(CLEAR_VARS)
LOCAL_MODULE := libThree
LOCAL_SRC_FILES := third.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../libOne $(LOCAL_PATH)/../libTwo
LOCAL_STATIC_LIBRARIES := libOne libTwo
include $(BUILD_SHARED_LIBRARY)
There is an android section in the projects' properties, where you can edit the library dependencies. It can only be used, if libOne libTwo and libThree are marked as libraries, in their properties panel.
Is there a macro or command to copy files? I'd like a 3rd party library (libThirdParty.so) to be copied to the output directory (lib). This is the contents of my Android.mk file
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndkFoo
LOCAL_SRC_FILES := ndkFoo.c
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
I have a build step I added for one of my .cpp files that's generated; you could do something similar.
Note that I was told that what I was doing was Not Supported by Google, so use at your own risk. I've been using something like the code below for more than a year, though. Here's a rough idea of what it would look like:
LOCAL_PATH:= $(call my-dir)
# this was important for some cases; can't remember if it's important here, but I don't want to steer you wrong if it isn't
REAL_LOCAL_PATH:=$(LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE := ndkFoo
# again, I'm being paranoid here
REAL_LOCAL_MODULE := $(LOCAL_MODULE)
LOCAL_SRC_FILES := ndkFoo.c
$(REAL_LOCAL_PATH)/obj/local/armeabi/$(REAL_LOCAL_MODULE).so : $(REAL_LOCAL_PATH)/libs/armeabi/libThirdParty.so
$(REAL_LOCAL_PATH)/libs/armeabi/libThirdParty.so : $(PATH_TO_LIB_THIRD_PARTY)/libThirdParty.so
cp $(PATH_TO_LIB_THIRD_PARTY)/libThirdParty.so $(REAL_LOCAL_PATH)/libs/armeabi/libThirdParty.so
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
Note you'll need to define PATH_TO_LIB_THIRD_PARTY.
ALSO note that copy-and-paste may or may not work. Makefiles are notoriously picky about indents. I'd make sure that the "cp" line has a real tab indent, and that nothing else is indented. If "cp" doesn't work, then make may be delegating to CMD, and you can try "copy" instead.
Good luck.
I know this thread is old, but found it while searching for something myself.
From the PowerVR SDK, Android.mk file.
You can create folders and copy files.
PVRSDKDIR := $(LOCAL_PATH)
ASSETDIR := $(PVRSDKDIR)/TrainingCourse/IntroducingPOD/OGLES2/Build/Android/assets
$(ASSETDIR):
-mkdir $(ASSETDIR)
$(ASSETDIR)/tex_base.pvr: $(ASSETDIR) $(PVRSDKDIR)/TrainingCourse/IntroducingPOD/OGLES2/tex_base.pvr
cp "$(PVRSDKDIR)/TrainingCourse/IntroducingPOD/OGLES2/tex_base.pvr" "$(ASSETDIR)/"
Google has a feature that is exactly intended for your use case: PREBUILT_SHARED_LIBRARY
If you check the documentation in the docs directory included in the NDK, you will find ANDROID-MK.html which mentions this feature briefly, and PREBUILTS.html which completely documents the feature. You can specify the source and destination directories, and you can specify a new name for the file when it is copied.
There is also PREBUILD_STATIC_LIBRARY which does the same thing for a static library.
It might be possible to trick it into copying arbitrary files... the above features are implemented by files called, respectively, prebuilt-shared-library.mk and prebuilt-static-library.mk. Inside, they define an extension that must be on the file (respectively .so and .a). You could probably make another .mk file that defined some other extension to enable copying some other kind of file. But we have only needed to copy libraries and we haven't experimented with trying to trick the build system.
P.S. This blog posting is interesting. It refers to BUILD_PREBUILT, which doesn't exist in my copy of the NDK. I wonder if this blog posting refers to an earlier version of the NDK, which had BUILD_PREBUILT to copy any kind of file (with no check for a required extension).
http://karthiksden.blogspot.com/2011/03/copying-data-files-using-androidmk.html
I'm trying to create a shared library that links to another shared library.
Here is my main module Android.mk:
TOP_LOCAL_PATH := $(call my-dir)
include $(call all-subdir-makefiles)
LOCAL_PATH := $(TOP_LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/ $(LOCAL_PATH)/lib/include
LOCAL_MODULE := SightCore-jni
LOCAL_SRC_FILES := SightDemo.cpp SightCore-jni.cpp
LOCAL_SHARED_LIBRARIES := SightAPI
LOCAL_LDLIBS = -llog
include $(BUILD_SHARED_LIBRARY)
I also have the prebuilt shared library in ./lib directory with its own Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := SightAPI
LOCAL_SRC_FILES := libSightAPI.so
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
The SightCore-jni.cpp source file is the jni interface to the shared library and is loaded using the command
System.loadLibrary("SightCore-jni");
During the ndk-build process I get no compilation or linkage errors.
When I try to run the application and access one of the native methods I get the UnsatsfiedLinkError.
I noticed that if disable the references to the SightAPI in my jni code and put a typo to the LOCAL_STATIC_LIBRARIES := SightAPI line, The build is successful and there is no UnsatisfiedLinkError.
This mean that the jni code I have is good (I'm actually sure it is ok...)
So the observation is as follows:
If I compile the shared library with the prebuilt shared library I get a corrupted .so file.
If I compile the same ndk project without linking to the prebuilt shared library there is no problem loading the shared library from the java side.
Please help me out if you can.
Thanks in advance,
Ita
Found the issue.
Apparently the ndk build system doesn't automatically load referenced shared libraries, even if they are declared in your Android.mk.
I had to call on System.loadLibrary(SightAPI) & System.loadLibrary("SightCore-jni") in order to solve this issue. I would have expected that the only library to load would have been the main library SightCore-jni.
Well..I guess the moral is If you want something done, do it yourself :)
+1 to Roy Samuel for his effort and correct instincts.
I hope this helps anyone.
Cheers
Have you made sure that the cpp function name, that you'd like to use over JNI, is corresponding to the package name of the Java wrapper class where System.loadLibrary("SightCore-jni"); is present?
e.g. If you would like to use the C function, myFunction in the java layer, and suppose your JNI wrapper class is in the package com.my.package.sightcore,
then your C code function name should be like this :
JNIEXPORT JNICALL Java_com_my_package_sightcore_myFunction(JNIEnv * env, jobject thiz, ...)
If you are running your app on your device,
See if the API levels, and hence, the sdk release matches to your device's android version (API level).
Hope this helps. Let me know if you need more clarifications...
This happened to me, and the solution for me was to make sure I was including the proper file libgnustl_shared.so and not libc++_shared.so after I switched compilers. So, just making sure either one of these files is the correct one for your build, and making sure it's been updated with the latest, you shouldn't get this issue any longer.