I am a android NDK newbie, I am trying to follow the documentation at https://developer.android.com/ndk/guides/prebuilts and I found it is unclear on how to setup the code.
So to declare a prebuilt library, it shows the first step:
Give the module a name. This name does not need to be the same as that
of the prebuilt library, itself.
Question 1: What does this mean by giving the module a name? rename the module folder? is this the folder usually called jni/? does it matter where this folder should be?
Question 2: If I don't find this jni/ folder, should I just add one by creating a new folder or right clicked on my project in android studio to add new module? I did the right click thing and there is no such module for native c++ libs.
the second step:
In the module's Android.mk file, assign to LOCAL_SRC_FILES ...
Question 3: Should I create the 1Android.mk` file by myself? if it is a must, why not have it generated automatically?
I then tried to follow the documentation at https://developer.android.com/studio/projects/add-native-code#new-project but there is no such Android.mk file created...
Anyway, in the Android.mk file it has something like this:
include $(CLEAR_VARS)
LOCAL_MODULE := foo-user
LOCAL_SRC_FILES := foo-user.c
LOCAL_SHARED_LIBRARIES := foo-prebuilt
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(BUILD_SHARED_LIBRARY)
Question 4: On the documentation page, where variables like PREBUILT_SHARED_LIBRARY BUILD_SHARED_LIBRARY is defined? can these path can be any place in the system as long I define it with full path?
Question 5: for LOCAL_PATH, I understand it is the local path where the Android.mk file locates, does that mean 1) the system will find this file automatically, 2) I can only have one folder with Android.mk if I want to use native libs?
Related
I'm trying to make use of a prebuilt dynamic library in a Flutter (v2.2.1) Android application.
I've placed the compiled libs into the android/app/src/main/jniLibs folder under target specific sub-folders, and they're picked up correctly by the build system and I can load the library with DynamicLibrary.open().
The library is written with Rust, but it makes use of a C++ library and I'm getting the error dlopen failed: cannot locate symbol "__cxa_pure_virtual" referenced by...
So my question is, how exactly do I tell the build system to link against the C++ runtime?
The Android 'C++ library support' page explains that the default runtime for ndk-build is none, and that I should add APP_STL := c++_shared to my Application.mk file.
Up until this point I didn't have an Application.mk file, but I could see that adding one might make sense, so I added the APP_STL definition to android/app/jni/Application.mk, and after some reading I decided that I should also add an Android.mk file (I don't know if it's actually required), with the following contents:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
From what I understand these then need to be picked up by Gradle, so in android/app/build.gradle I've added:
...
android {
...
externalNativeBuild {
ndkBuild {
path 'jni/Android.mk'
path 'jni/Application.mk'
}
}
}
Unfortunately this doesn't have any effect (I get the same error, and inspecting the APK shows that libc++_shared.so hasn't been included). I'm at the point where I'm thinking there's surely a simpler way to tell the build system to link against libc++_shared.so?
If I'm going down the right path, any ideas for why isn't my APP_STL definition being applied?
I guess you should put libc++_shared.so into dir:android/app/src/main/jniLibs.
I want to create a c++ project for android ndk.And I want to use it every project like dynamic library.I dont want to change /transport source code every time.I import *.so file and include it and use its class or whatever.
This is possible.If it possible how could import and use it.
Or i create java project and i use it to communicate c++ project with using jni and i compile it.After that i have a *.jar file and i use it instead of android ndk.
Which one of them possible or effective.
I'm not entirely sure if I understood the question correctly, but I assume you prefer to write your Android applications using solely/mostly C++ and have a core library/module that you want to re-use for every consecutive project WITHOUT including that libraries SOURCE files in each consecutive project.
You can omit including the source files and include the final built .so file in your new project by adding the required libraries into your makefile. Like so:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := (includes for libraryname)
LOCAL_MODULE := libraryname
LOCAL_SRC_FILES := libraryname.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
--- instructions for custom application code here ---
LOCAL_SHARED_LIBRARIES := libraryname
Where "libraryname" is the name of the library module and "libraryname.so" is the name of the library file. Note the path should be relative to the make file. Below the second "include $(CLEAR_VARS)" and above the final "LOCAL_SHARED_LIBRARIES" you add the instructions for building the source code of the application which is to use the shared library.
Don't forget to load all libraries in order on the Java side, i.e.:
System.loadLibrary( "libraryname" );
System.loadLibrary( "customlib" );
I'm trying to build a project using the android ndk (on Windows), and I'm having some issues specifically with the source files (LOCAL_SRC_FILES in the Android.mk)
I'm trying to use relative paths to a parent folder such as
LOCAL_SRC_FILES := ../../../src/main.cpp
And when running ndk_build.cmd, it outputs the following error:
Compile++ thumb : GTP <= main.cpp
The system cannot find the file specified.
make: *** [obj/local/armeabi/objs/GTP/__/__/__/src/.o] Error 1
So I tried using absolute paths:
LOCAL_SRC_FILES := D:/Path/To/src/main.cpp
Unfortunately this doesn't work because the : causes issues on windows
Is there any way I can specify source files in a relative directory (or absolute)? The reason I am asking is because I want to avoid making a symbolic link to the src folder if possible.
According to ndk documentation it is recommended to use relative paths and the following macro (Android.mk uses syntax of make files):
LOCAL_PATH := $(call my-dir)
An Android.mk file must begin with the definition of the LOCAL_PATH variable.
It is used to locate source files in the development tree. In this example,
the macro function 'my-dir', provided by the build system, is used to return
the path of the current directory (i.e. the directory containing the
Android.mk file itself).
So you can replace your LOCAL_SRC_FILES with something similar to:
LOCAL_SRC_FILES := $(LOCAL_PATH)/../../../src/main.cpp
The easiest way to work with source files spread across many directories, is to compile separate static libraries for each directory or group of directories. In NDK, these libraries are called "modules". For each module, you specify LOCAL_SRC_PATH in Android.mk. LOCAL_SRC_FILES are relative to this path. The caveat is that LOCAL_C_INCLUDES etc. are relative to project root directory (usually, the one above the jni directory).
You can have many Android.mk files in your project, but you can build many modules with single Android.mk.
Try this:
LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := YOUR_SRC_IN_LIB_JNI
I'm currently implementing a custom Logging mechanism that I need to be accessible from both native and Java code. The fundamentals of the logging are implemented in C/C++ with a Java wrapper, and the two together are being built as an android Library Project.
The issue at hand is that while my Java code can access the Library project output, there doesn't seem to be a way for my native code to access the native .so or headers from the Library project. Is there an additional step I'm missing or is this just a limitation of the current ADT? More specifically, is there a makefile/eclipse configuration that will address the things I'm used to getting out of Library projects in general? (Build .so as needed, import rebuilt .so, import relevant headers for c/c++ compilation, etc.)
I don't think it's a limitation. We are supposed to declare native code dependencies in Android.mk and Application.mk
Worked out a way to get what I wanted - most of the information is (of course) in the NDK documentation, but what I was trying to do isn't 100% supported within the ADT. It should also be noted that I'm currently stuck developing in a windows environment, so much of this might be easier or unnecessary in Linux. The first key is the $(call import-module ...) macro. Within your library project, move the source files and the Android.mk folder into a named directory you can locate later. My Library project directory looked like this:
MyProject
> src
> res
v jni
- Application.mk
v MyLib
- source.cpp
- source.h
- Android.mk
I also had to edit my Application.mk to point to the project:
APP_PROJECT_PATH := <path-to-my-project>
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/jni/MyProject/Android.mk
Annoyingly, this broke my Android.mk in ways unforseen until I added a ./ to my source files. Also you need to export your includes for linking:
LOCAL_SRC_FILES := ./source.cpp
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
Ensure that the system path variable NDK_MODULE_PATH is set to include your library's JNI directory, e.g. <path-to-my-project>/jni (Note: I had to restart eclipse after I did this).
In the receiving application's Android.mk file (the one you'd like to link natively to your app), import the module:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyNativeProject
LOCAL_SRC_FILES := source.cpp
LOCAL_CFLAGS := -DANDROID_NDK -g -std=c99
LOCAL_SHARED_LIBRARIES := MyLib
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
$(call import-module, IntelLog)
At this point everything built perfectly, but the APK packager didn't like the generated .so binary being included twice (once from the Library project's natural import process, and again from the import-module call). To solve this, clean the library and don't build it again! the import-module call will build the .so and import it into your project. (Obviously, if your project only requires the Java API, you would need that .so file to be built). Congratulations! you have a functional (if not straightforward) build process with a hybrid native/Java Library
This question seems to have been asked a lot but all were trying to use eclipse to package the library inside the APK.
However, my requirement is to package the library inside the APK (which will later be loaded using System.loadLibrary() through Java) using the Android build system, i.e. i want to write an Android.mk file that does this job.
Requirement:
1. Prebuilt shared library: libTest.so
2. Write an Android.mk file that will package this to libs/armeabi-7 inside the apk.
I don't know much about the build system I am using but the compilation is done using "mm" command after exporting the required environment variables.
When I provide libTest for LOCAL_JNI_SHARED_LIBRARIES, it tries to find it inside its exported paths and fails to find it there and hence build fails.
Can anyone please give any pointers on writing an Android.mk file that will package my prebuild shared library into the APK?
In order to prebuild your native library you have to
Create jni folder in your project folder
Create libs folder in your project folder
Add Adnroid.mk make file to the jni folder, it should looks like
this:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := Test
LOCAL_SRC_FILES := Test.cpp
include $(BUILD_SHARED_LIBRARY)
Note 1: Test.cpp is the main library source file containing implementation of native methods. You can add more sources as a space separated list.
Note 2: Do not include headers, they are included automatically.
Note 3: If you need to enable C++ STL, then create another make file - Application.mk, add it to the jni folder and set APP_STL := stlport_static flag in it.
Then you will have to set up a builder. Refer to this article for how to do that:
After these steps, the builder will create your library in the libs folder which will be automatically packed into the apk when building the whole application.
Note: Your library name should be lowercase, it is a Linux convention. The "lib" prefix will be automatically added, so the final library name will be libtest.so.
Let's say there is one libxxx.so shared library under libs/armeabi/ of project which you want to pack into apk. There are 2 things you need to do in the Android.mk as below:
# 1. Copy .so to out/target/product/***/obj/lib
$(shell cp $(wildcard $(LOCAL_PATH)/libs/armeabi/*.so $(TARGET_OUT_INTERMEDIATE_LIBRARIES))
# 2. Make libxxx to be packed into apk
LOCAL_JNI_SHARED_LIBRARIES := libs/libxxxx
Then you can use apktool to unpack the built apk, you will find the libxxx.so will be located in libs/armeabi*/. It is indeed packed into the apk.
I had two LOCAL_JNI_SHARED_LIBRARIES that I wanted to build into my APK. I manage to do it by setting the following in my Android.mk:
LOCAL_MODULE_TAGS := samples
After re-compiling the module I was able to find both libraries inside the .apk under /lib/.