futimes function not present with API version 28 selected while cross compiling - android

I am trying to cross compile PuTTY utilities to run under Termux and despite using API level 28 it says the function 'futimes' is not present.
Here is where it gets stuck:
/home/xb/Desktop/android-ndk-r21d/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang -DHAVE_CONFIG_H -I. -I././ -I./charset/ -I./windows/ -I./unix/ -Wall -Werror -Wpointer-arith -Wvla -g -O2 -MT unix/uxsftpserver.o -MD -MP -MF $depbase.Tpo -c -o unix/uxsftpserver.o unix/uxsftpserver.c &&\
mv -f $depbase.Tpo $depbase.Po
unix/uxsftpserver.c:472:18: error: implicit declaration of function 'futimes' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
SETSTAT_GUTS(FD_PREFIX, fd, attrs, success);
^
You can browse the source file in question by downloading PuTTY source code version 0.74.
This page shows futimes was added in API version 26.
I am aware of the binary package for PuTTY avaliable in Termux's repo, I just want to learn how to cross compile.

The issue is that while we may have our minimum SDK version to be 26, we do not have the __USE_BSD macro defined, not adding the definition.
#if defined(__USE_BSD)
#if __ANDROID_API__ >= 26
int futimes(int __fd, const struct timeval __times[2]) __INTRODUCED_IN(26);
int lutimes(const char* __path, const struct timeval __times[2]) __INTRODUCED_IN(26);
#endif /* __ANDROID_API__ >= 26 */
#endif
sys/time.h source (same as above)
Looking deeper into where that macro is defined, we see this definition:
/*
* With bionic, you always get all C and POSIX API.
*
* If you want BSD and/or GNU extensions, _BSD_SOURCE and/or _GNU_SOURCE are
* expected to be defined by callers before *any* standard header file is
* included.
*
* In our header files we test against __USE_BSD and __USE_GNU.
*/
#if defined(_GNU_SOURCE)
# define __USE_BSD 1
# define __USE_GNU 1
#endif
#if defined(_BSD_SOURCE)
# define __USE_BSD 1
#endif
sys/cdefs.h source (same as above)
As a result, we must add either _GNU_SOURCE or _BSD_SOURCE as a compiler cFlag, which in gradle looks as such:
android {
compileSdkVersion 30
...
defaultConfig {
minSdkVersion 26
targetSdkVersion 30
...
externalNativeBuild {
cmake {
cFlags "-D_BSD_SOURCE" // or cFlags "-D_GNU_SOURCE"
...
}
}
}
It turns out that it is not necessarily guaranteed anywhere that NDK will use those flags, as shown by the comment in sys/cdefs.h. Instead, we have to provide the preprocessor macro definition ourselves.

Related

How to use cpu-feature in a native library?

We recently added cpu-features to detect platform features like ARMV8 and CRC, AES and SHA. We caught a bug report for building against the latest NDK. When we attempt to include <cpu-features.h> in an armeabi project it results in:
$ make -f GNUmakefile-cross
arm-linux-androideabi-g++ -DNDEBUG -g2 -O3 -fPIC -pipe -march=armv5te -mtune=xscale -mthumb -msoft-float
-funwind-tables -fexceptions -frtti -DANDROID --sysroot=/opt/android-ndk/platforms/android-21/arch-arm
-Wa,--noexecstack -I/opt/android-ndk/sources/cxx-stl/gnu-libstdc++/4.9/include
-I/opt/android-ndk/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi/include -c cpu.cpp
In file included from cpu.cpp:26:0:
/opt/android-ndk/platforms/android-21/arch-arm/usr/include/machine/cpu-features.h:52:6: error:
# error Unknown or unsupported ARM architecture
^
cpu.cpp: In function 'bool CryptoPP::CPU_QueryNEON()':
cpu.cpp:402:29: error: 'android_getCpuFeatures' was not declared in this scope
if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)
^
cpu.cpp:402:33: error: 'ANDROID_CPU_ARM_FEATURE_NEON' was not declared in this scope
if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)
^
make: *** [cpu.o] Error 1
The CXXFLAGS we are using come directly from a JNI project I created a few years ago. I used ndk-build to examine the flags Android's build system sets, and then transferred them to our script. We are not making them up; they are official NDK compiler options.
When I cat the header cpu-features.h I see an ominous sign:
/* __ARM_ARCH__ is a number corresponding to the ARM revision
* we're going to support. Our toolchain doesn't define __ARM_ARCH__
* so try to guess it.
*/
#ifndef __ARM_ARCH__
# if defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ || \
defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__
# define __ARM_ARCH__ 7
# elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ || \
defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6Z__ || \
defined __ARM_ARCH_6KZ__ || defined __ARM_ARCH_6T2__
# define __ARM_ARCH__ 6
# else
# error Unknown or unsupported ARM architecture
# endif
#endif
We seem to be missing something in our process and implementation. First, all the definitions needed are provided by the preprocessor (see below). The preprocessor provides __ARM_ARCH, but Android's header checks for __ARM_ARCH__.
Second, <machine/cpu-features.h> does not seem to include needed declarations:
$ cat /opt/android-ndk/platforms/android-21/arch-arm/usr/include/machine/cpu-features.h | grep -i android_getCpuFeatures
$
We don't use Android's build system, so very little of this applies: The cpufeatures Library. Its also too high level and lacks some of the details we need.
My question is, how do we use cpu-features in a regular native library? What are we missing for the first and second problems?
Our script sets CXX, CXXFLAGS, etc. They are available for use once the script is sourced. In this case:
$ echo $CXX
arm-linux-androideabi-g++
And:
$ $CXX -dM -E - </dev/null | sort
#define __ACCUM_EPSILON__ 0x1P-15K
#define __ACCUM_FBIT__ 15
#define __ACCUM_IBIT__ 16
#define __ACCUM_MAX__ 0X7FFFFFFFP-15K
#define __ACCUM_MIN__ (-0X1P15K-0X1P15K)
#define __ANDROID__ 1
#define __APCS_32__ 1
#define __arm__ 1
#define __ARM_32BIT_STATE 1
#define __ARM_ARCH 5
#define __ARM_ARCH_5TE__ 1
#define __ARM_ARCH_ISA_ARM 1
#define __ARM_ARCH_ISA_THUMB 1
#define __ARM_EABI__ 1
#define __ARMEL__ 1
#define __ARM_FEATURE_CLZ 1
#define __ARM_FEATURE_DSP 1
#define __ARM_FEATURE_QBIT 1
#define __ARM_FP 12
#define __ARM_NEON_FP 4
#define __ARM_PCS 1
#define __ARM_SIZEOF_MINIMAL_ENUM 4
#define __ARM_SIZEOF_WCHAR_T 4
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_ACQUIRE 2
#define __ATOMIC_CONSUME 1
#define __ATOMIC_RELAXED 0
#define __ATOMIC_RELEASE 3
#define __ATOMIC_SEQ_CST 5
#define __BIGGEST_ALIGNMENT__ 8
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
...
None of the cpu-features seem to be declared or defined:
$ echo $AOSP_SYSROOT
/opt/android-ndk/platforms/android-21/arch-arm
$ grep -IR android_getCpuFeatures $AOSP_SYSROOT
$ grep -IR ANDROID_CPU_ARM_FEATURE_NEON $AOSP_SYSROOT
$
The library isn't prebuilt as part of the NDK, but is shipped as source. When building with ndk-build, this library can be built automatically by referencing it, but when using an external build system, you need to make sure to include and build it yourself.
The source is in android-ndk/sources/android/cpufeatures, and there you'll find a different cpu-features.h. (In order to reach the one you found, you probably included machine/cpu-features.h instead, which is a completely diffrent thing.)
So you need to include cpu-features.h from android-ndk/sources/android/cpufeatures and build cpu-features.c as part of your build process. Or if you're producing a static library, it can also be enough to build your code against this header, and document that the user of the library needs to include the cpufeatures library when producing the final shared library.

Building OpenCV for Android and using it with the NDK

Context : I am currently developing an app on Android Studio for the Moverio BT 200 augmented reality glasses. I am using OpenCV, and specifically, the arUco module of the library. This module has to be used with the NDK. Also, it is not on the stable release, so I compiled the library myself (using this guide : https://zami0xzami.wordpress.com/2016/03/17/building-opencv-for-android-from-source/). The build of the library went well. After that, I made a android studio project (customOCVtest). I did it the way I always do when using OpenCV with Android Studio and the NDK, except this time it was with the custom build. I checked if the library was correctly loaded :
private static final String OCVdevTAG = "OCVmainAct";
static {
System.loadLibrary("native-lib");
if(!OpenCVLoader.initDebug()) {
Log.d(OCVdevTAG, "OpenCV not loaded");
} else {
Log.d(OCVdevTAG, "OpenCV loaded");
}
}
The library is indeed loaded when I build.
Now comes the problem : When I try to actually use the arUco module in my native code (here is my native-lib.cpp) :
#include <jni.h>
#include <string>
#include <opencv2/aruco.hpp>
extern "C" {
jstring
Java_com_jambonsama_customocvtest_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
cv::Ptr<cv::aruco::Dictionary> dict = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Mat marker;
cv::aruco::drawMarker(dict, 25, 200, marker, 1);
return env->NewStringUTF(hello.c_str());
}
}
the gradle sync works, but I can't build. I get the following error :
Error:FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
Error while executing 'C:\Users\JambonSama\AppData\Local\Android\Sdk\cmake\3.6.3155560\bin\cmake.exe' with arguments {--build C:\Users\JambonSama\AndroidStudioProjects\customOCVtest\app\.externalNativeBuild\cmake\debug\mips64 --target native-lib}
[1/1] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\mips64\libnative-lib.so
FAILED: cmd.exe /C "cd . && C:\Users\JambonSama\AppData\Local\Android\sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe -target mips64el-none-linux-android -gcc-toolchain C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64 --sysroot=C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/platforms/android-21/arch-mips64 -fPIC -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -fno-exceptions -fno-rtti -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -fno-exceptions -fno-rtti -O0 -fno-limit-debug-info -O0 -fno-limit-debug-info -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libnative-lib.so -o ..\..\..\..\build\intermediates\cmake\debug\obj\mips64\libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_aruco.a -llog -lm "C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/mips64/libgnustl_static.a" && cd ."
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
C:/Users/JambonSama/AppData/Local/Android/sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/windows-x86_64/lib/gcc/mips64el-linux-android/4.9.x/../../../../mips64el-linux-android/bin\ld: C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a(alloc.cpp.o): Relocations in generic ELF (EM: 40)
C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a: error adding symbols: File in wrong format
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
In particular, this error message tells me that I tried to build with the following argument :
{--build C:\Users\JambonSama\AndroidStudioProjects\customOCVtest\app\.externalNativeBuild\cmake\debug\mips64 --target native-lib}
This argument is automatically generated by AS, and I can't find the file where it is passed. I believe that if I can find it, I can build for arm (which is what I want), instead of mips. The thing is, I can't find it. (And I'm not even sure that is indeed what I'm looking for. I'm just trying to make my project build for my glasses.)
Here after is my CMakeLists.txt :
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
src/main/cpp/native-lib.cpp )
include_directories(C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/jni/include)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_core.a
C:/Libs/opencv_src/opencv/platforms/build_android_arm/install/sdk/native/libs/armeabi-v7a/libopencv_aruco.a
# Links the target library to the log library
# included in the NDK.
${log-lib} )
here is my app build.gradle :
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.1"
defaultConfig {
applicationId "com.jambonsama.customocvtest"
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
sourceSets { main { jni.srcDirs = ['src/main/jni', 'src/main/jniLibs/'] } }
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.1'
testCompile 'junit:junit:4.12'
compile project(':openCVLibrary310dev')
}
and my openCVLibrary310dev build.gradle
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "23.0.2"
defaultConfig {
ndk {
abiFilter("armeabi-v7a")
}
minSdkVersion 14
targetSdkVersion 25
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
What I tried, mainly by just copying stuff that helped other people solve problems that seemed similar to mines :
#set(CMAKE_SYSTEM_NAME Android)
or
#set(CMAKE_TOOLCHAIN_FILE "Toolchain file" CACHE FILEPATH "C:/Libs/opencv_src/opencv/platforms/android.toolchain.cmake")
or
#set( CMAKE_CXX_COMPILER "C:/Libs/android-ndk-r13b/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++.exe" )
in the CMakeLists.txt
and
splits {
abi {
enable true
reset()
include 'armeabi-v7a'
universalApk true
}
}
or
tasks.getByPath(":app:linkMipsDebugRemoteDesktopSharedLibrary").enabled = false
in the build.gradle (I tried both because I didn't know which one was supposed to have it).
Except for the very last bit of code (the task.getByPath...), the sync worked, but I couldn't build. For the last one, I couldn't even sync.
I also tried to rebuild the library for mips, since the architecture seems to be the problem, but I have no idea how to do that.
Where can I find the file where the following argument :
{--build C:\Users\JambonSama\AndroidStudioProjects\customOCVtest\app\.externalNativeBuild\cmake\debug\mips64 --target native-lib}
is passed when building? And / or how do I make Android Studio build my project for arm architecture?
So the mips architecture problem can be solved by adding the following code to the gradle.build of app, at the end of the android block :
productFlavors {
armv7 {
ndk {
abiFilter "armeabi-v7a"
}
}
fat
}
But then, other problems arised. Notably, the library is built with the carotene options, which Android Studio doesn't like, and then, the gzlib misses, so Android Studio can't build and / or run. So after MANY trials, I finally achieved what I wanted : cross-compilation of openCV with extra modules for Android on Windows, and building an AS project with said built library so that it works. I documented my whole proccess, from downloading the openCV sources up until running my application on my arm-architected device, I'll just copy paste it here for anyone who needs to do that too. The following instructions are mainly based on this tutorial (thank you to Zamrath Nizam who wrote it). The only problem with that tutorial is that it's probably a little old, so some options / steps need to be altered.
CROSS COMPILE OPENCV FROM SOURCE WITH EXTRA MODULES FOR ANDROID FROM WINDOWS10
* FIRST : prerequisites *
download OpenCV and unzip (say at '../opencv-source')
download OpenCV extra modules and unzip (say at '../opencv-contrib-source')
download Android NDK (say at '../ndk-dir')
download CMake (to say '../cmake-dir') and MinGW (to say '../mingw-dir')
install Android Studio
* SECOND : configure with CMake *
go to '../opencv-source/platforms' and create a folder named 'build_android_arm'
in CMake, fill the following first two fields with the following paths :
where is the source code : '../opencv-source'
where to build the binaries : '../opencv-source/platforms/build_android_arm'
add the following options via the 'Add Entry' :
ANDROID_NDK, type 'path', value '../ndk-dir'
ANDROID_NDK_HOST_X64, type 'bool', value 1
CMAKE_TOOLCHAIN_FILE, type 'path', value '../opencv-source/platforms/android/android.toolchain.cmake'
press 'Configure'
choose 'MinGW Makefiles' as the compiler
choose 'Specify toolchain file for cross-compiling'
press 'Next', and 'Finish'
note 1 : As long as you've got no error message, everything's good. Don't worry about the warning messages (like CMake telling you you're doing deprecated stuff).
note 2 : If you can't configure at that step, try to read the next few points, it might help.
change the following additional options via the 'Search' field :
EXTRA_MODULE_PATH, type 'path', value '../opencv-contrib-source/modules'
WITH_CAROTENE, type 'bool', value 0
BUILD_ZLIB, type 'bool', value 1
note : You MUST have configured already once before this step, because the variables created before are regrouped under the group 'Ungrouped entries', while the following variables are CMake automatically generated variables, and NEED to be grouped in the right groups (which is NOT 'Ungrouped entries').
verify that the following options are correctly set up (via the 'Search' field) :
ANDROID_NDK_HOST_X64, type 'bool', value 1
CMAKE_MAKE_PROGRAM, type 'path', value '../mingw-dir/bin/mingw32-make.exe'. This option, I actually DIDN'T have it in my CMake config. IF when you press 'Configure', it doesn't work AND you don't have this option, then you should try adding it (but I don't know how). IF when you press 'Configure' you don't have any problem, don't bother about that variable. This check comes from the original tutorial linked above.
CMAKE_TOOLCHAIN_FILE, type 'path', value '../opencv-source/platforms/android/android.toolchain.cmake'
press 'Configure'
choose 'MinGW Makefiles' as the compiler
choose 'Specify toolchain file for cross-compiling'
press 'Next', and 'Finish'
press 'Generate'
* THIRD : compile with mingw *
go to '../mingw-dir/msys/1.0' and run 'msys' bash file
navigate to '../opencv-source/platforms/android_arm'
run 'mingw32-make' command
run 'mingw32-make install' command
* FOURTH : android project *
launch Android Studio and create a new project :
select File -> New -> New Project...
fill the 'Application name' with let's say 'cOCV'
check the 'Include C++ Support' box
click 'Next'
choose your min SDK (let's say API 14: Android 4.0 (IceCreamSandwich)
click 'Next', 'Next' and 'Finish'
go to File -> New -> Import Module...
provide '../opencv-source/platforms/android_arm/install/sdk/java'
click 'Next' and 'Finish'
change the targets in build.gradle file in openCVLibraryXXX (imported module) folder :
compileSdkVersion and targetSdkVersion should be the same, greater or equal to 23
minSdkVersioon should be the same as the one specified when creating the project
in the build.gradle file in openCVLibraryXXX (imported module) folder :
replace 'apply plugin: com.android.application' as, 'apply plugin: com.android.library'
remove the line 'applicationId "org.opencv"'
note : That last step is done in order to avoid following error : 'unspecified on project app resolves to an APK archive which is not supported as a compilation dependency'.
add the imported library as a dependency to the 'app' module in File->'Project Structure'
create a jniLibs folder in 'app/src/main' :
right click 'app' in the Android view on the left menu
click 'New-Folder-JNI Folder'
check the 'Change Folder Location'
set the 'Target Source Set as 'app/src/main/jniLibs'
copy libraries of OpenCV from 'opencv-source/platforms/android_arm/install/sdk/native/libs'
into the newly created folder (jniLibs) inside the
'AndroidStudioProjects/cOCV/app/src/main/jniLibs' folder
note : For example, my AndroidStudioProjects folder is located at 'C:\Users\JambonSama\AndroidStudioProjects'.
in 'opencv-contrib-source/modules/module_you_desperately_need/CMakeLists.txt', change 'ocv_define_module(module_you_desperately_need opencv some other modules)' for 'ocv_define_module(module_you_desperately_need opencv some other modules WRAP java)'
note 1 : THIS STEP MAY BE USELESS, because WRAP java is probably already written in the file.
note 2 : If 'python' is written too, it's fine, you let it be written where it is.
in CMakeLists.txt, add :
the following two lines after the 'add_library' block and before the 'find_library' block :
include_directories(../opencv_src/opencv/platforms/build_android_armn/install/sdk/native/jni/include)
link_directories(../AndroidStudioProjects/cOCVn/app/src/main/jniLibs/armeabi-v7a)
note : These two lines pretty straight-forwardly give the paths for the include and link directories
the following lines after the 'find_library' block and before the 'target_link_libraries' block :
file(GLOB PARTYLIBS "../opencv_src/opencv/platforms/build_android_armn/install/sdk/native/3rdparty/libs/armeabi-v7a/*.a")
file(GLOB CVLIBS "../opencv_src/opencv/platforms/build_android_armn/install/sdk/native/libs/armeabi-v7a/*.a")
note : These are for easier linking commands, see next point.
the following paths, AS WRITTEN, in the 'target_link_libraries', after the 'native-lib' variable, and before the '${log-lib}' one :
${CVLIBS}
${PARTYLIBS}
${CVLIBS}
note : THAT IS THE TRICKY PART : because of cyclical dependencies, you have to write CVLIBS, PARTYLIBS, and then CVLIBS a second time, otherwise you won't stop having linking errors. By now, everything should be linked.
in the gradle.build of app, add the following code :
productFlavors {
armv7 {
ndk {
abiFilter "armeabi-v7a"
}
}
fat
}
at the end of the android block
note : This prevents the mips64 architecture error at build, by specifying once and for all the arm architecture
in the native-lib.cpp :
try the following code in the 'stringFromJNI' function (this one is automatically generated by AS when the project is created)
cv::Mat test;
cv::VideoCapture camera;
camera.open(0);
cv::Ptrcv::aruco::Dictionary dict = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);
cv::Mat marker;
cv::aruco::drawMarker(dict, 25, 200, marker, 1);
std::string hello = "Hello from C++";
return env-NewStringUTF(hello.c_str());
don't forget the following includes :
#include jni.h
#include string
#include opencv2/aruco.hpp
#include opencv2/videoio.hpp
note : Because the string is not generated before the end of the function, you know, when you test, that if the string is indeed displayed on screen, the function has been gone through without problem, and that you're good (since the above provided code use some modules that are not on the stable realease as of 08/12/2016 (8th of december, I write dates with a dd/mm/yyyy format).
time to test :
sync the gradle
build
run on an arm device
You're good to go \ o \\ O // o /
Additional notes :
All the gradle.build files and the CMakeLists.txt file can be easily found on the Android View in the menu on the left of the window in AS.
Remember if you've got errors navigating in the command window that maybe your '/' should be '\' or the other way round. ('cd' command to navigate in a command window).
I run on Windows10.
If you're not quite sure what you should see on screen steps by steps, the tutorial I mentioned at the beginning of the answer should give you a good idea what you're supposed to see up until the AS project creation. Then, you can give a look at this tutorial, which explains how to setup OpenCV SDK in Android Studio project FOR THE OFFICIAL RELEASE. The steps I provided differs from BOTH those tutorials, but I put them here, because they can help you know what your screen / windows should look like.

Different behavior of override weak function in shared library between OS X and Android

I am encountering a different behavior between OS X and Android:
There is a weak function foo in my shared library,
I want to override it with strong function defined in my executable.
I expect the the overridden also affect the calling inside the library
Result: I got expected result on OS X, but failed on Android.
Here is my test project:
File: shared.h
void library_call_foo();
void __attribute__((weak)) foo();
File: shared.c
#include "shared.h"
#include <stdio.h>
void library_call_foo()
{
printf("shared library call foo -> ");
foo();
}
void foo()
{
printf("weak foo in library\n");
}
File: main.c
#include <stdio.h>
#include <shared.h>
void foo()
{
printf("strong foo in main\n");
}
int main()
{
library_call_foo();
printf("main call foo -> ");
foo();
return 0;
}
I compile & run it in OS X use commands:
clang -shared -fPIC -o libshared.so shared.c
clang -I. -L. -lshared -o test main.c
./test
which return results as I expected:
shared library call foo -> strong foo in main
main call foo -> strong foo in main
But when I compile it for Android with NDK toolchains use same commands:
arm-linux-androideabi-clang -shared -fPIC -o libshared.so shared.c
arm-linux-androideabi-clang -I. -L. -lshared -o test main.c
and run it on device, I got different results:
shared library call foo -> weak foo in library
main call foo -> strong foo in main
Why is the behaviors are different, and how could I fix it?
Android dynamic linker does in fact support weak symbols. The problem is this particular case is that library is compiled with -Bsymbolic (to check this run "readelf -d libshared.so").
The work around this is to use '-Wl,-shared' instead of '-shared' when linking the library.
Please see https://code.google.com/p/android/issues/detail?id=68956 for details and workaround.
Android doesn't support weak symbol override.
In the recent release android-5.0.2_r1,
see the comment at line 539 in linker.cpp source code
/*
*
* Notes on weak symbols:
* The ELF specs are ambigious about treatment of weak definitions in
* dynamic linking. Some systems return the first definition found
* and some the first non-weak definition. This is system dependent.
* Here we return the first definition found for simplicity.
*/
This comment exists from version 2.2_r1 (which is in linker.c) to newest version 5.0.2_r1

C++11 std::async in Android NDK does not work

I have tried to get following sample code working to know whether asynchronous programming is working in Android NDK. Though NDK has the STL <future> which gets recognized as a header, the std::async is not getting recognized are not getting recognized. The code I tried to use was the following:
#include <future>
#include <iostream>
struct Foo
{
Foo() : data(0) {}
void sum(int i) { data +=i;}
int data;
};
int main()
{
Foo foo;
auto f = std::async(&Foo::sum, &foo, 42);
f.get();
std::cout << foo.data << "\n";
}
Also all the include paths have been set to the specified folder under Properties->Paths and Symbols
Errors
Description Resource Path Location Type
invalid use of incomplete type 'std::__async_sfinae_helper<void (Foo::*)(int), void (Foo::*)(int), Foo*, int>::type {aka struct std::future<void>}' Sample.cpp /Project12/jni line 50 C/C++ Problem
Description Resource Path Location Type
declaration of 'std::__async_sfinae_helper<void (Foo::*)(int), void (Foo::*)(int), Foo*, int>::type {aka struct std::future<void>}' Project12 line 111, external location: D:\android-ndk-r8e-windows-x86_64\android-ndk-r8e\sources\cxx-stl\gnu-libstdc++\4.6\include\future C/C++ Problem
Curently Android NDK does not incorporate all of the C++11 features. Clang 3.3 compiler from NDK r9b is C++11-feature complete, however, STL and stdlib on Android are not.
To use the most recent C++11 feature set in Android use Clang 3.3 compiler from Android NDK r9b. Put this line into your Application.mk file:
NDK_TOOLCHAIN_VERSION := clang
Also, add -std=c++11 switch to the LOCAL_CPPFLAGS variable:
LOCAL_CPPFLAGS += -std=c++11

GCC 4.4.3 offsetof constant expression bug. How should I work around this?

I have a struct that contains a static constant expression that uses the offset macro defined in stddef.h
struct SomeType {
int m_member;
};
static const size_t memberOffset = offsetof(SomeType, m_member);
in GCC 4.4.3 (I'm using Androids NDK r7) this generates the following error:
arm-linux-androideabi-g++ -MMD -MP -MF ./obj/local/armeabi-v7a/... -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fno-exceptions -fno-rtti -O2 -fomit-frame-pointer -fstrict-aliasing -funswitch-loops -finline-limit=300 - -I/Users/Byron/bin/android-ndk-r7/sources/cxx-stl/system/include -
-Wa,--noexecstack -O0 -g -w -D_ANDROID -I/blah/bin/android-ndk-r7/platforms/android-14/arch-arm/usr/include -c
/MyFile.h:330: error: '->' cannot appear in a constant-expression
/MyFile.h:330: error: '&' cannot appear in a constant-expression
This seems like a compiler bug. Does anyone have a good workaround for this? I found references to a bug of this nature on GCC 3.4 but not later versions. hmmm
Standards
In the C++98 standard, there's some information in
C.2.4.1 Macro offsetof(type, memberdesignator) [diff.offsetof]
The macro offsetof, defined in <cstddef>, accepts a restricted set of type arguments in this International
Standard. §18.1 describes the change.
(C.2.4.1 showed up with offsetof in the contents, so I went there first.) And:
§18.1 Types 18 Language support library
¶5 The macro offsetof accepts a restricted set of type arguments in this International Standard. type
shall be a POD structure or a POD union (clause 9). The result of applying the offsetof macro to a field that
is a static data member or a function member is undefined.
For comparison, the C99 standard says:
offsetof(type, member-designator)
which expands to an integer constant expression that has type size_t, the value of
which is the offset in bytes, to the structure member (designated by member-designator),
from the beginning of its structure (designated by type). The type and member designator
shall be such that given
static type t;
then the expression &(t.member-designator) evaluates to an address constant. (If the
specified member is a bit-field, the behavior is undefined.)
Your code
Your code meets the requirements of both the C++ and C standards, it seems to me.
When I use G++ 4.1.2 and GCC 4.5.1 on RedHat (RHEL 5), this code compiles without complaint with the -Wall -Wextra options:
#include <cstddef>
struct SomeType {
int m_member;
};
static const int memberOffset = offsetof(SomeType, m_member);
It also compiles without complaint with #include <stddef.h> and with the GCC compilers (if I use struct SomeType in the macro invocation).
I wonder - I got errors until I included <cstddef>...did you include that? I also added the type int to the declaration, of course.
Assuming that you haven't made any bloopers in your code, it seems to me that you probably have found a bug in the <cstddef> (or <stddef.h>) header on your platform. You should not be getting the error, and the Linux-based G++ appears to confirm that.
Workarounds?
You will need to review how offsetof() is defined in your system headers. You will then probably redefine it in such a way as not to run into the problem.
You might be able to use something like this, assuming you identify your broken system somehow and execute #define BROKEN_OFFSETOF_MACRO (or add -DBROKEN_OFFSETOF_MACRO to the command line).
#include <cstddef>
#ifdef BROKEN_OFFSETOF_MACRO
#undef offsetof
#define offsetof(type, member) ((size_t)((char *)&(*(type *)0).member - \
(char *)&(*(type *)0)))
#endif /* BROKEN_OFFSETOF_MACRO */
struct SomeType {
int m_member;
};
static const int memberOffset = offsetof(SomeType, m_member);
The size_t cast is present since the difference between two addresses is a ptrdiff_t and the offset() macro is defined to return size_t. The macro is nothing other than ugly, but that's why it is normally hidden in a system header where you don't have to look at it in all its ghastliness. But when all else fails, you must do whatever is necessary.
I know that once, circa 1990, I encountered a C compiler that would not allow 0 but it would allow 1024 instead. The distributed <stddef.h> header, of course, used 0, so I 'fixed' it by changing the 0 to 1024 (twice) for the duration (until I got a better compiler on a better machine).
offsetof() must be defined using pointer arithmetic.
GCC probably doesn't like that in constant expressions because in theory the pointers could change and so it is non-const.
Workaround might be make it a static int without const?

Categories

Resources