I use Qt Creator to compile an Android application. I needed to integrate OpenCV into it, and it took me half a day to configure it properly, so I want to document the steps I took here, in case somebody else ever has to do it.
Edit: For OpenCV 4.x see the answers below. My answer was tested on OpenCV 2.4 only.
Original answer:
First, I downloaded OpenCV-2.4.10-android-sdk, and put into my project directory. It contains static libraries, and link order matters for static libraries for GCC. So you need to order them just so. This is how my .pro file looked in the end ($$_PRO_FILE_PWD_ refers to the project directory):
INCLUDEPATH += "$$_PRO_FILE_PWD_/OpenCV-2.4.10-android-sdk/sdk/native/jni/include"
android {
LIBS += \
-L"$$_PRO_FILE_PWD_/OpenCV-2.4.10-android-sdk/sdk/native/3rdparty/libs/armeabi-v7a"\
-L"$$_PRO_FILE_PWD_/OpenCV-2.4.10-android-sdk/sdk/native/libs/armeabi-v7a"\
-llibtiff\
-llibjpeg\
-llibjasper\
-llibpng\
-lIlmImf\
-ltbb\
-lopencv_core\
-lopencv_androidcamera\
-lopencv_flann\
-lopencv_imgproc\
-lopencv_highgui\
-lopencv_features2d\
-lopencv_calib3d\
-lopencv_ml\
-lopencv_objdetect\
-lopencv_video\
-lopencv_contrib\
-lopencv_photo\
-lopencv_java\
-lopencv_legacy\
-lopencv_ocl\
-lopencv_stitching\
-lopencv_superres\
-lopencv_ts\
-lopencv_videostab
ANDROID_PACKAGE_SOURCE_DIR=$$_PRO_FILE_PWD_/android
}
After that the project will compile but it will fail to run with the error
E/AndroidRuntime(11873): java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1891]: 176 could not load needed library 'libopencv_java.so' for 'libMyProject.so' (load_library[1093]: Library 'libopencv_java.so' not found)
To overcome this, you need to add libopencv_java.so to your APK, and then manually load it from QtActivity.java. That's what the ANDROID_PACKAGE_SOURCE_DIR=$$_PRO_FILE_PWD_/android line at the end was for. Now you need to place libopencv_java.so here:
project_root/android/libs/armeabi-v7a/libopencv_java.so
project_root/android/src/org/qtproject/qt5/android/bindings/QtActivity.java
You can get QtActivity.java from the Android target build directory, in my case the full path was c:\Workspace\build-MyProject-Android_for_armeabi_v7a_GCC_4_9_Qt_5_4_0-Debug\android-build\src\org\qtproject\qt5\android\bindings\QtActivity.java, and just copy it.
Then you find those lines in it:
// now load the application library so it's accessible from this class loader
if (libName != null)
System.loadLibrary(libName);
And load libopencv_java.so before them, so they become:
// This is needed for OpenCV!!!
System.loadLibrary("opencv_java");
// now load the application library so it's accessible from this class loader
if (libName != null)
System.loadLibrary(libName);
Note that you pass opencv_java to System.loadLibrary(), even though the file is libopencv_java.so.
Edit: I forgot to mention, but I already had installed OpenCV Manager on my phone when trying to run one of the samples that come with OpenCV-2.4.10-android-sdk, so I don't know if it's needed or not. In any event, keep it in mind, if it fail even after my steps, you might need to download OpenCV Manager (it's available on the Google Store).
Edit 2: I'm using adt-bundle-windows-x86-20140702, android-ndk-r10d, OpenCV-2.4.10-android-sdk, Qt Creator 3.3.0, and my build target is "Android for armeabi-v7a (GCC 4.9, Qt 5.4.0)".
Edit 3: From Daniel Saner's comment:
In OpenCV 3.x, opencv_java has been renamed to opencv_java3. Also, while I didn't look into the specific changes that might have effected this, the workaround regarding that library in the final step seems to no longer be necessary. The app compiles and runs without the ANDROID_PACKAGE_SOURCE_DIR line
Edit 4: #myk's comment:
Worked for me with OpenCV 3.2. To workaround the build issues with carotene finish the LIBS+ section with: -lopencv_videostab\ -ltegra_hal\ – myk 2 hours ago
For OpenCV 4, sashoalm's approach did not work for me until I adapted it:
Download the Android-Pack and unzip it somewhere. We'll create a qmake-variable OPENCV_ANDROID which points to that directory later.
Add the following snippet to your *.pro-file:
android {
contains(ANDROID_TARGET_ARCH,arm64-v8a) {
isEmpty(OPENCV_ANDROID) {
error("Let OPENCV_ANDROID point to the opencv-android-sdk, recommended: v4.0")
}
INCLUDEPATH += "$$OPENCV_ANDROID/sdk/native/jni/include"
LIBS += \
-L"$$OPENCV_ANDROID/sdk/native/libs/arm64-v8a" \
-L"$$OPENCV_ANDROID/sdk/native/3rdparty/libs/arm64-v8a" \
-llibtiff \
-llibjpeg-turbo \
-llibjasper \
-llibpng \
-lIlmImf \
-ltbb \
-lopencv_java4 \
ANDROID_EXTRA_LIBS = $$OPENCV_ANDROID/sdk/native/libs/arm64-v8a/libopencv_java4.so
} else {
error("Unsupported architecture: $$ANDROID_TARGET_ARCH")
}
}
This will work for the arm64-v8a only. If you happen to build for another architecture (apparently 32-Bit is still the default for Qt#Android), you must change the .../libs/arm64-v8a part of the paths (occurs 3 times) and the same to match your actual target-architecture (the contains(...)-part in the second line of the snippet).
Tell qmake where to find the SDK. Add the following to qmake-call: "OPENCV_ANDROID=/path/to/OpenCV-android-sdk".
e.g., this looks like qmake example.pro "OPENCV_ANDROID=/home/user/OpenCV-android-sdk" from command line.
when you use QtCreator, add "OPENCV_ANDROID=..." to the "Additional arguments"-field. You can find it after enabling the Project-Mode in the Build-section of the android-kit. Expand the qmake-field under Build Steps
Starting from Android android-ndk-r18b, with Qt Creator 4.9.x kits, I could not use the openCV-4.1.1 pre-compiled shared libraries (.so) with Qt Android ABI armeabi-v7a target and ABI arm64-v8a, as Opencv standard is based on GCC, While the NDK-r18b removed gcc and uses clang compiler. ( I am getting
Fatal signal 11 (SIGSEGV), code 1
On initialize calling android_getCpuFeatures() when the application starts)
Thus, openCV shared libs must be compiled from sources for clang in order to be used with Qt Android kits.
This reference Compiling OpenCV on Android from C++ (Without OpenCVManager) was of real help. I would leave a reference here as well for a simple procedure I used under windows 10, to get opencv compiled with NDK 18 (clang) for Qt Android:
Downloaded openCV source code
Downloaded openCV contrib source for selected openCV version
Used cmake for windows
in the unzipped opencv source folder, created a new build folder.
MinGW from Qt installation can generally be used for building, So I used Qt 5.11.x (MinGW 5.3.0 32 bit) command line tool from Qt menu.
from command line, in new build folder, I could generate cmake configuration :
C:\opencv-4.1.1\build> "C:\program files\cmake\bin\cmake" .. -G"MinGW Makefiles"
-DBUILD_SHARED_LIBS=ON
-DANDROID_STL=c++_shared
-DANDROID_ABI="armeabi-v7a with NEON"
-DANDROID_NATIVE_API_LEVEL=23
-DANDROID_TOOLCHAIN=clang
-DCMAKE_TOOLCHAIN_FILE=D:\Qt\android-ndk-r18b\build\cmake\android.toolchain.cmake
-DANDROID_NDK=D:\Qt\android-ndk-r18b
-DANDROID_SDK=C:\Users\moham\AppData\Local\Android\sdk
-DCMAKE_BUILD_TYPE=Debug
-DBUILD_ANDROID_PROJECTS=OFF
-DWITH_OPENCL=ON -DWITH_TBB=ON -DENABLE_NEON=ON
-DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF
-DBUILD_FAT_JAVA_LIB=OFF
Then , C:\opencv-4.1.1\build>\mingw32-make -jx and C:\opencv-4.1.1\build>\mingw32-make install
the result libs can be picked from opencv-4.1.1\build\install folder
Link in Qt Android project:
android {
#opencv
OPENCVLIBS = $$PWD/../opencv-4.1.1\build\install/sdk/native
INCLUDEPATH = $$OPENCVLIBS/jni/include
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
# might need libs to be copied into app's library folder and loaded on start-up, in case android ships older libs??!
ANDROID_EXTRA_LIBS = \
$$OPENCVLIBS/libs/armeabi-v7a/libopencv_core.so \
$$OPENCVLIBS/libs/armeabi-v7a/libopencv_imgproc.so \
$$OPENCVLIBS/libs/armeabi-v7a/libtbb.so
LIBS += -L"$$OPENCVLIBS/libs/armeabi-v7a"\
-lopencv_core -lopencv_imgproc -ltbb
}
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
}
Also, copy the libs to ANDROID_PACKAGE_SOURCE_DIR
Note: If detailed control over cmake configuration is needed, cmake windows gui can be used, while not a must and not tested. AmMIN's procedure is helpful for cmake tool, remember to add flag for shared Android STL.
Related
I'm trying to build PJSIP with FFMPEG for Android.
For building FFMPEG with rtmp and openssl, I use this project:
https://github.com/cine-io/android-ffmpeg-with-rtmp
and it compiles pretty well.
Then I'm compiling pjsip 2.6 with ffmpeg. Here is the part from my build file:
APP_PLATFORM=android-${TARGET_ANDROID_API} NDK_TOOLCHAIN_VERSION=4.9 TARGET_ABI=$arch ./configure-android --use-ndk-cflags \
--with-ssl="${OPENSSL_BUILD_OUT_PATH}/libs/${arch}" \
--with-ffmpeg="${BASE_DIR}/ffmpeg-output"
>>"${FINAL_BUILD_LOGS}/${arch}.log" 2>&1
My target ABI is armeabi.
Also, i've defined these two flags:
#define PJMEDIA_HAS_VIDEO 1
#define PJMEDIA_HAS_FFMPEG 1
But the build failed with a bunch of these two errors:
error: cannot find -lbz2
error: cannot find -lasound
A have libasound2-dev and bzip2 installed on my Ubuntu 16.04 LTS VM.
Before that, I've successfully made pjsip builds with OpenH264 with no errors like this.
Is there any way to tell linker(or whatever it is) how to find those packages?
Solve that problem (thx #NandhaKumar) by compiling .a libs for each library above and adding them to pjsip library path:
Build .a libs.
Copy libs to {PJPROJECT}/third_party/lib/ folder.
Go to the build.mak.in file in your PJSIP project folder.
Add the following lines:
APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libbz2.a
APP_THIRD_PARTY_LIB_FILES += $(PJ_DIR)/third_party/lib/libasound.a
In my case (and I still don't know why) second line and defining another line
(APP_THIRD_PARTY_LIBS += -lsound or APP_THIRD_PARTY_LIBS += -lasound) doesn't help, so I just copied this library into the android_ndk folder:
android-ndk-r10e/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9/libasound.a
I use Qt Creator to compile an Android application. I needed to integrate OpenCV into it, and it took me half a day to configure it properly, so I want to document the steps I took here, in case somebody else ever has to do it.
Edit: For OpenCV 4.x see the answers below. My answer was tested on OpenCV 2.4 only.
Original answer:
First, I downloaded OpenCV-2.4.10-android-sdk, and put into my project directory. It contains static libraries, and link order matters for static libraries for GCC. So you need to order them just so. This is how my .pro file looked in the end ($$_PRO_FILE_PWD_ refers to the project directory):
INCLUDEPATH += "$$_PRO_FILE_PWD_/OpenCV-2.4.10-android-sdk/sdk/native/jni/include"
android {
LIBS += \
-L"$$_PRO_FILE_PWD_/OpenCV-2.4.10-android-sdk/sdk/native/3rdparty/libs/armeabi-v7a"\
-L"$$_PRO_FILE_PWD_/OpenCV-2.4.10-android-sdk/sdk/native/libs/armeabi-v7a"\
-llibtiff\
-llibjpeg\
-llibjasper\
-llibpng\
-lIlmImf\
-ltbb\
-lopencv_core\
-lopencv_androidcamera\
-lopencv_flann\
-lopencv_imgproc\
-lopencv_highgui\
-lopencv_features2d\
-lopencv_calib3d\
-lopencv_ml\
-lopencv_objdetect\
-lopencv_video\
-lopencv_contrib\
-lopencv_photo\
-lopencv_java\
-lopencv_legacy\
-lopencv_ocl\
-lopencv_stitching\
-lopencv_superres\
-lopencv_ts\
-lopencv_videostab
ANDROID_PACKAGE_SOURCE_DIR=$$_PRO_FILE_PWD_/android
}
After that the project will compile but it will fail to run with the error
E/AndroidRuntime(11873): java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1891]: 176 could not load needed library 'libopencv_java.so' for 'libMyProject.so' (load_library[1093]: Library 'libopencv_java.so' not found)
To overcome this, you need to add libopencv_java.so to your APK, and then manually load it from QtActivity.java. That's what the ANDROID_PACKAGE_SOURCE_DIR=$$_PRO_FILE_PWD_/android line at the end was for. Now you need to place libopencv_java.so here:
project_root/android/libs/armeabi-v7a/libopencv_java.so
project_root/android/src/org/qtproject/qt5/android/bindings/QtActivity.java
You can get QtActivity.java from the Android target build directory, in my case the full path was c:\Workspace\build-MyProject-Android_for_armeabi_v7a_GCC_4_9_Qt_5_4_0-Debug\android-build\src\org\qtproject\qt5\android\bindings\QtActivity.java, and just copy it.
Then you find those lines in it:
// now load the application library so it's accessible from this class loader
if (libName != null)
System.loadLibrary(libName);
And load libopencv_java.so before them, so they become:
// This is needed for OpenCV!!!
System.loadLibrary("opencv_java");
// now load the application library so it's accessible from this class loader
if (libName != null)
System.loadLibrary(libName);
Note that you pass opencv_java to System.loadLibrary(), even though the file is libopencv_java.so.
Edit: I forgot to mention, but I already had installed OpenCV Manager on my phone when trying to run one of the samples that come with OpenCV-2.4.10-android-sdk, so I don't know if it's needed or not. In any event, keep it in mind, if it fail even after my steps, you might need to download OpenCV Manager (it's available on the Google Store).
Edit 2: I'm using adt-bundle-windows-x86-20140702, android-ndk-r10d, OpenCV-2.4.10-android-sdk, Qt Creator 3.3.0, and my build target is "Android for armeabi-v7a (GCC 4.9, Qt 5.4.0)".
Edit 3: From Daniel Saner's comment:
In OpenCV 3.x, opencv_java has been renamed to opencv_java3. Also, while I didn't look into the specific changes that might have effected this, the workaround regarding that library in the final step seems to no longer be necessary. The app compiles and runs without the ANDROID_PACKAGE_SOURCE_DIR line
Edit 4: #myk's comment:
Worked for me with OpenCV 3.2. To workaround the build issues with carotene finish the LIBS+ section with: -lopencv_videostab\ -ltegra_hal\ – myk 2 hours ago
For OpenCV 4, sashoalm's approach did not work for me until I adapted it:
Download the Android-Pack and unzip it somewhere. We'll create a qmake-variable OPENCV_ANDROID which points to that directory later.
Add the following snippet to your *.pro-file:
android {
contains(ANDROID_TARGET_ARCH,arm64-v8a) {
isEmpty(OPENCV_ANDROID) {
error("Let OPENCV_ANDROID point to the opencv-android-sdk, recommended: v4.0")
}
INCLUDEPATH += "$$OPENCV_ANDROID/sdk/native/jni/include"
LIBS += \
-L"$$OPENCV_ANDROID/sdk/native/libs/arm64-v8a" \
-L"$$OPENCV_ANDROID/sdk/native/3rdparty/libs/arm64-v8a" \
-llibtiff \
-llibjpeg-turbo \
-llibjasper \
-llibpng \
-lIlmImf \
-ltbb \
-lopencv_java4 \
ANDROID_EXTRA_LIBS = $$OPENCV_ANDROID/sdk/native/libs/arm64-v8a/libopencv_java4.so
} else {
error("Unsupported architecture: $$ANDROID_TARGET_ARCH")
}
}
This will work for the arm64-v8a only. If you happen to build for another architecture (apparently 32-Bit is still the default for Qt#Android), you must change the .../libs/arm64-v8a part of the paths (occurs 3 times) and the same to match your actual target-architecture (the contains(...)-part in the second line of the snippet).
Tell qmake where to find the SDK. Add the following to qmake-call: "OPENCV_ANDROID=/path/to/OpenCV-android-sdk".
e.g., this looks like qmake example.pro "OPENCV_ANDROID=/home/user/OpenCV-android-sdk" from command line.
when you use QtCreator, add "OPENCV_ANDROID=..." to the "Additional arguments"-field. You can find it after enabling the Project-Mode in the Build-section of the android-kit. Expand the qmake-field under Build Steps
Starting from Android android-ndk-r18b, with Qt Creator 4.9.x kits, I could not use the openCV-4.1.1 pre-compiled shared libraries (.so) with Qt Android ABI armeabi-v7a target and ABI arm64-v8a, as Opencv standard is based on GCC, While the NDK-r18b removed gcc and uses clang compiler. ( I am getting
Fatal signal 11 (SIGSEGV), code 1
On initialize calling android_getCpuFeatures() when the application starts)
Thus, openCV shared libs must be compiled from sources for clang in order to be used with Qt Android kits.
This reference Compiling OpenCV on Android from C++ (Without OpenCVManager) was of real help. I would leave a reference here as well for a simple procedure I used under windows 10, to get opencv compiled with NDK 18 (clang) for Qt Android:
Downloaded openCV source code
Downloaded openCV contrib source for selected openCV version
Used cmake for windows
in the unzipped opencv source folder, created a new build folder.
MinGW from Qt installation can generally be used for building, So I used Qt 5.11.x (MinGW 5.3.0 32 bit) command line tool from Qt menu.
from command line, in new build folder, I could generate cmake configuration :
C:\opencv-4.1.1\build> "C:\program files\cmake\bin\cmake" .. -G"MinGW Makefiles"
-DBUILD_SHARED_LIBS=ON
-DANDROID_STL=c++_shared
-DANDROID_ABI="armeabi-v7a with NEON"
-DANDROID_NATIVE_API_LEVEL=23
-DANDROID_TOOLCHAIN=clang
-DCMAKE_TOOLCHAIN_FILE=D:\Qt\android-ndk-r18b\build\cmake\android.toolchain.cmake
-DANDROID_NDK=D:\Qt\android-ndk-r18b
-DANDROID_SDK=C:\Users\moham\AppData\Local\Android\sdk
-DCMAKE_BUILD_TYPE=Debug
-DBUILD_ANDROID_PROJECTS=OFF
-DWITH_OPENCL=ON -DWITH_TBB=ON -DENABLE_NEON=ON
-DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF
-DBUILD_FAT_JAVA_LIB=OFF
Then , C:\opencv-4.1.1\build>\mingw32-make -jx and C:\opencv-4.1.1\build>\mingw32-make install
the result libs can be picked from opencv-4.1.1\build\install folder
Link in Qt Android project:
android {
#opencv
OPENCVLIBS = $$PWD/../opencv-4.1.1\build\install/sdk/native
INCLUDEPATH = $$OPENCVLIBS/jni/include
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
# might need libs to be copied into app's library folder and loaded on start-up, in case android ships older libs??!
ANDROID_EXTRA_LIBS = \
$$OPENCVLIBS/libs/armeabi-v7a/libopencv_core.so \
$$OPENCVLIBS/libs/armeabi-v7a/libopencv_imgproc.so \
$$OPENCVLIBS/libs/armeabi-v7a/libtbb.so
LIBS += -L"$$OPENCVLIBS/libs/armeabi-v7a"\
-lopencv_core -lopencv_imgproc -ltbb
}
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
}
Also, copy the libs to ANDROID_PACKAGE_SOURCE_DIR
Note: If detailed control over cmake configuration is needed, cmake windows gui can be used, while not a must and not tested. AmMIN's procedure is helpful for cmake tool, remember to add flag for shared Android STL.
I'm experimenting with a rooted Android tablet. I need to run some system applications in C/C++ that can run as native apps with/without using the NDK. This would work like existing command line applications such as toolbox as a native ARM Linux executable.
Is that a possibility?
Yes, you can. And you can do it using the NDK which you make things easier to you , cross-compiling to all platforms supported by Android (ARM variants and x86). You just need to do like you would do to create a shared library for native Java methods. Just make sure you change the makefile to use BUILD_EXECUTABLE instead of BUILD_SHARED_LIBRARY to create an executable. Of course you won't need the APK folder structure, just the "jni" folder.
Tutorial
Create the project folders:
mkdir project_folder
cd project_folder/jni
NDK_PROJECT_PATH=<path to>/project_folder
Create the Android.mk makefile in the jni folder
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := teste
LOCAL_SRC_FILES := teste.c
include $(BUILD_EXECUTABLE)
Create also your source code in the jni. In this case, you can see from above makefile, it is teste.c:
#include <stdio.h>
int main (){
puts("Hello World");
return 0;
}
Now go up to your project folder and run ndk-build from there:
# ~/Downloads/android-ndk-r8b/ndk-build
Compile thumb : teste <= teste.c
Executable : teste
Install : teste => libs/armeabi/teste
Although it is output to a lib folder it is a executable, as you can inspect with file
#file libs/armeabi/teste
libs/armeabi/teste: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
Yes, it's possible. When you download the NDK you get a set of tools (compiler, linker, etc.), headers and libraries. It's not significantly different from other cross compilation environments.
The NDK comes with a cross compiler and enough of a freestanding programming environment (includes and libs) to port simple C/C++ applications to run as native Android binaries. Check out the docs/STANDALONE-TOOLCHAIN.html file in the NDK for documentation. (It's available online at kandroid.com.)
I believe that the NDK does not have access to enough system services to write a complete app. You'll still have to write the scaffolding of the app in Java, but you can write plenty of native libraries for the Java to call.
I have a really simple helloworld.cpp program
#include <iostream>
using namespace std;
int main ()
{
cout << "Hello World!";
return 0;
}
And I'm trying to compile it for android x86 with the cross-compiler from the toolchain:
/Users/me/android-ndk-r8/toolchains/x86-4.4.3/prebuilt/darwin-x86/bin/i686-android-linux-g++ helloworld.cpp -L "/Users/me/android-ndk-r8/sources/cxx-stl/stlport/libs/x86/" -lstlport_static
However, I get errors:
helloworld.cpp:2:20: error: iostream: No such file or directory
Any idea why?
Check the documentation.html file included with the NDK, under "Standalone Toolchain". It says that if you invoke the compiler in this way you won't be able to "use any C++ STL". However it is possible, as the documentation explains, if you first create a "customized" toolchain installation, using something like the following command:
$NDK/build/tools/make-standalone-toolchain.sh --platform=android-8 --install-dir=/tmp/my-android-toolchain --arch=x86
where $NDK is the path to your NDK directory. Note the --arch=x86 which means that the toolchain is prepared specifically for the x86 Android. This prepares what you need in one directory, including the STL headers and folders. You should then be able to use -lstdc++ to link against the STL (static version), i.e. something like:
/tmp/my-android-toolchain/bin/i686-android-linux-g++ helloworld.cpp -lstdc++
For a more complete explanation, please see the NDK documentation.
The NDK documentation is not entirely accurate, at least not currently. In fact, it states when using the prebuilt toolchain "You won't be able to use any C++ STL (either STLport or the GNU libstdc++) with it.", but this is out of date. I created a small hello world program using the include with the same error. It can be solved without creating your own toolchain though, which is nice if you don't want to have to add one more step to your configuration process and allows you to always use the latest SDK platform without creating a new toolchain every time.
The NDK ships with the source code for several versions of standard C++ libraries: GAbi++, STLport, and GNU STL. Each flavor comes with prebuilt shared and static libs as well. My example below will use stlport.
To use the stand-alone toolchain at its installed location, you can do something like this:
export CXX='$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ --sysroot="$NDK_ROOT/platforms/android-19/arch-arm"'
This, for example, would set your CXX compiler to compile ARM on the OS X system using SDK platform level 19. This much you probably already knew. Also, you would want to export your CC, CPP, LD, AR, and RANLIB if you use it. I also personally create an envar for READELF.
To add support for C++ libs, you could do something like follows:
$CXX helloworld.cpp -I$NDK_ROOT/sources/cxx-stl/stlport/stlport -L$NDK_ROOT/sources/cxx-stl/stlport/libs/armeabi -lstlport_shared
Note that this will link the libstlport_shared.so which will now be required at runtime, so you may need to add a relative path to the command above to support that, depending on your APK structure. If you want to just test this simple case, you can just run this on the emulator as follows:
adb push a.out /data
adb push $NDK_ROOT/sources/cxx-stl/stlport/libs/armeabi/libstlport_shared.so /data
adb shell
# su
# cd /data
# chmod 777 a.out
# ./a.out
To get rid of the headache of dealing with shared library paths, you can also statically link the C++ library in by changing "-lstlport_shared" to "-lstlport_static". There are some consequences of doing this, as explained in the NDK Dev Guide. The biggest issue is due to having the static library linked in multiple places, causing:
- memory allocated in one library, and freed in the other would leak or even corrupt the heap.
- exceptions raised in libfoo.so cannot be caught in libbar.so (and may simply crash the program).
- the buffering of std::cout not working properly
A useful tool is also included to see what dependencies your program has, the readelf tool.
To see what other shared libraries your program requires, you can run the following:
$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-readelf -a a.out | grep NEEDED
Other cool standard tools:
addr2line - convert a stack trace address to a line of code
nm - Displays the symbol table
objdump - displays info on an object
i call one of the functions from gnustl after it runs fine from prebuilt aosp arm-linux-androideabi-gcc --std=c++11 and after crashing error i cant get a backtrace from logs or reason, my hope is turning to crossbuilt qemu-linux-user to run host compiled i686 binary on the arm, difficulty is interacting with crosshost libs aapt from adt always crashes on any other than platform specific libs, unless kernel module packaged update is possible...
I need to build the latest OpenSSL (1.0.0g) for an Android application. I am trying to follow the example given by https://github.com/fries/android-external-openssl, but I just can't get it built.
I am running Windows 7 Professional (64-bit) with a complete and recent Cygwin. I have installed the Android SDK and NDK, and I can successfully build and run the NDK's hello-jni sample application.
I created a new sample NDK app called hello-openssl. In its jni directory, I created an openssl directory. There, I unzipped https://github.com/fries/android-external-openssl/zipball/master, which gave me this tree structure under c:\android\android-ndk\samples\hello-openssl:
jni
+- openssl
+- apps
+- crypto
+- include
+- openssl
+- ssl
I then modified the Android.mk file in the jni directory in an attempt to include the OpenSSL files:
subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
openssl \
))
include $(subdirs)
Now when I execute ndk-build, it compiles several .c files, but then quickly fails:
Compile thumb : crypto <= cryptlib.c
In file included from jni/openssl/crypto/cryptlib.c:117:
jni/openssl/crypto/cryptlib.h:65:18: error: e_os.h: No such file or directory
jni/openssl/crypto/cryptlib.h:72:28: error: openssl/crypto.h: No such file or directory
I found http://osdir.com/ml/android-ndk/2010-07/msg00424.html, which tells me to "add
jni and jni/include to the above LOCAL_C_INCLUDES" in crypto/Android.mk, but I can't figure out the syntax I should use to achieve this.
I also can't figure out of I have the correct directory structure.
I sincerely appreciate any help that can be offered.
Thanks!
I solved this problem by abandoning https://github.com/fries/android-external-openssl and instead using https://github.com/guardianproject/openssl-android.
It is based on a more recent OpenSSL (1.0.0a), and it builds in the NDK without any modifications.
Note that in order to use these libraries in an Android app, you must rename them. If you simply include the resulting libssl.so and libcrypto.so in your app, then call System.LoadLibrary ("crypto") and System.LoadLibrary ("ssl"), you will get the OpenSSL libraries included in the Android system, not your custom libraries.
To do this, just do a full-word search and replace ("libssl" -> "libsslx", and "libcrypto" -> "libcryptox") in each Android.mk (i.e, in /crypto, /ssl, and /apps).
Then in your Android app, call SystemLoadLibrary ("cryptox") and System.LoadLibrary ("sslx")