OpenCV - undefined reference to 'cv::CascadeClassifier::detectMultiScale()' after NDK update - android

Yesterday I updated my Android Studio included NDK to version 17.0.4754217and since then I can't run my app anymore. When I tried to rerun the code after the update it gave me the error ABIs [mips64, armeabi, mips] are not supported for platform. Supported ABIs are [armeabi-v7a, arm64-v8a, x86, x86_64] so I excluded them from the project in my app.gradle file the following way: abiFilters 'x86', 'x86_64', /*'armeabi',*/ 'armeabi-v7a', 'arm64-v8a'/*, 'mips', 'mips64'*/.
However, since then I'm having a problem with the C++-file where I use the OpenCV-function cv::CascadeClassifier::detectMultiScale.
It always displays the error: CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o: In function detectAndDisplay(cv::Mat, double, int, std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >, cv::CascadeClassifier&)':
D:\Schule\OpenCV\ARcpp\app\src\main\cpp/native-lib.cpp:158: undefined reference to cv::CascadeClassifier::detectMultiScale(cv::_InputArray const&, std::__ndk1::vector<cv::Rect_<int>, std::__ndk1::allocator<cv::Rect_<int> > >&, double, int, int, cv::Size_<int>, cv::Size_<int>)'.
I call the function like this: cascadeClassifier.detectMultiScale(frame_gray, sights, scaleFactor, minNeighbours, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));. The rest of the code is pretty much like shown in the OpenCV-tutorial https://docs.opencv.org/2.4/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.html.
Additionally to the NDK I use CMake and LLDB and my included OpenCV-library is openCVLibrary320. Again, all of this worked until I downloaded the mentioned NDK update.
The rest of the error that always appears on building or executing the app is: Build command failed.
Error while executing process C:\Users\chris\AppData\Local\Android\Sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build D:\Schule\OpenCV\ARcpp\app\.externalNativeBuild\cmake\debug\arm64-v8a --target native-lib}
[1/1] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\arm64-v8a\libnative-lib.so
FAILED: cmd.exe /C "cd . && C:\Users\chris\AppData\Local\Android\Sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=aarch64-none-linux-android --gcc-toolchain=C:/Users/chris/AppData/Local/Android/Sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64 --sysroot=C:/Users/chris/AppData/Local/Android/Sdk/ndk-bundle/sysroot -fPIC -isystem C:/Users/chris/AppData/Local/Android/Sdk/ndk-bundle/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -std=c++11 -frtti -fexceptions -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot C:/Users/chris/AppData/Local/Android/Sdk/ndk-bundle/platforms/android-21/arch-arm64 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -LC:/Users/chris/AppData/Local/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/arm64-v8a -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\arm64-v8a\libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o -llog ../../../../src/main/jniLibs/arm64-v8a/libopencv_java3.so -latomic -lm "C:/Users/chris/AppData/Local/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_static.a" "C:/Users/chris/AppData/Local/Android/Sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++abi.a" && cd ."
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
I`m really lost, hopefully someone knows an answer.

OpenCV is built with ANDROID_STL=gnustl_static. After upgrade, your NDK uses the default libc++ instead. You can set ANDROID_STL explicitly in your app/build.gradle:
android { defaultConfig { externalNativeBuild { cmake {
arguments '-DANDROID_STL=gnustl_static'
} } } }
(see an example here).

When linkin opencv with your project executables, you always have to link with the general library -lopencv_core. But some packages require additional link flags. For example,
if you use highgui as in
#include <opencv2/highgui/highgui.hpp>
you must add opencv_highgui link flag for : -lopencv_highgui.
In you case, CascadeClassifiers are defined in
#include "opencv2/objdetect.hpp"
and thus requires a link with opencv_objdetect -lopencv_objdetect.
The solution is to add the link flag -lopencv_objdetect when compiling.

A more complete answer for all the seekers out there. Using OpenCV prebuilt static libraries in your project with a native component.
This is what I have for the build.gradle:
defaultConfig {
minSdkVersion 21
targetSdkVersion 21
externalNativeBuild {
cmake {
cppFlags "-fexceptions -std=gnu++11"
arguments '-DANDROID_STL=gnustl_static'
}
}
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'armeabi-v7a', 'x86'
stl = "gnustl_shared"
}
}
This is the CMakeLists.txt:
set(OPENCV_LIBRARIES ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libopencv_video.a
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libopencv_imgproc.a
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libopencv_core.a
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libopencv_highgui.a
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libtbb.a
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libcpufeatures.a
)
if (${ANDROID_ABI} STREQUAL "x86")
set(OPENCV_LIBRARIES ${OPENCV_LIBRARIES}
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libippiw.a
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libippicv.a
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libittnotify.a
)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libippicv.a -Wl,--exclude-libs,libippiw.a")
endif()
if (${ANDROID_ABI} STREQUAL "armeabi-v7a")
set(OPENCV_LIBRARIES ${OPENCV_LIBRARIES}
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_NDK_ABI_NAME}/libtegra_hal.a
)
endif()
(then use ${OPENCV_LIBRARIES} for your target_link_libraries)

The first comment on this link can save you many hours which I copy past below:
"I had similar issue. In turned out that you got to use similar Android NDK as one that was used to build OpenCV Android SDK, that in case of versions ~3.4 is Android NDK 10. Recently, OpenCV Android SDK 4.0.1 have been released and it works with the newest NDK version (19 at the time)."
At the time of this post, you can find the release 4.1.2. You can check if there's a latest release on this link.
After you select your latest version, in this case 4.1.2, download the file opencv-4.1.2-android-sdk.zip, unzip it and copy the sdk/native folder to yourprojectfolder/your-app/src/sdk/.
You're ready to roll.

I solved this problem by using mix with this OpenCV + contrib lib (opencv4_1_0_contrib) and official Java OpenCV classes (4.3). Successfully run official OpenCV FaceDetection example on Android 9.
Some usefull code:
App level build.gradle:
android{defaultConfig{
//...
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions"
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
//I import OpenCV as module and provide it path to CMake
arguments "-DOpenCV_DIR=/" + rootProject.projectDir.path + "/sdk/native"
}
}
}}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
My CMakeLists.txt:
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
#Add OpenCV 4 lib
include_directories(${OpenCV_DIR}/jni/include) #Path from gradle to OpenCV Cmake
add_library( lib_opencv SHARED IMPORTED )
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${OpenCV_DIR}/libs/${ANDROID_ABI}/libopencv_java4.so)
#Add Your Native Lib
add_library(native-lib SHARED native-lib.cpp)
add_library(detection_based_tracker SHARED detectionbasedtracker_jni.cpp)
#Add&Link Android Native Log lib with others libs
find_library(log-lib log)
target_link_libraries(detection_based_tracker lib_opencv ${log-lib})
NDK version was 21.0.611669.
Also I don't use arguments for CMake like -DANDROID_STL=gnustl_static.

Related

Updating application with C++ native library to NDK 18, cmake isn't including required sysroot platform include directory

I have an Android application, developed with Android Studio, that is using a very old build system - NDK 14 with CMake 3.6 and AGP 3.5. I'm trying to update it to NDK 18 (I eventually want to update it to latest NDK, but baby steps) using CMake 3.18.1 and AGP 4.2.2 with Gradle 6.7.1, but the build fails due to errors finding a system include file asm/types.h.
Looking at the clang++ compile command that CMake generates, it is clearly missing the ${SYSROOT}/usr/include/<platform-abi> directory.
My CMake (which worked well for NDK 14 with CMake 3.6.1) has these lines:
if(${CMAKE_ANDROID_ARCH_ABI} STREQUAL arm64-v8a)
include_directories(${ANDROID_SYSROOT}/usr/include/aarch64-linux-android)
elseif(${CMAKE_ANDROID_ARCH_ABI} STREQUAL x86_64)
include_directories(${ANDROID_SYSROOT}/usr/include/x86_64-linux-android)
endif()
Running CMake with --trace-expand, I can see it correctly parses those lines:
…
… arm64Release|arm64-v8a :/home/…/myapp/mynativelib/CMakeLists.txt(5):
if(arm64-v8a STREQUAL arm64-v8a )
… arm64Release|arm64-v8a :/home/…/myapp/mynativelib/CMakeLists.txt(6):
include_directories(/home/…/Android/Sdk/ndk/18.1.5063045/sysroot/usr/include/aarch64-linux-android )
…
But the build.ninja file generated does not have this include directory - it contains compile directives that look like so:
build CMakeFiles/mynativelib.dir/home/…/mynativelib/MyClass.cpp.o: \
CXX_COMPILER__mynativelib_Debug /home/…/mynativelib/MyClass.cpp || \
cmake_object_order_depends_target_mynativelib
DEFINES = -DANDROID -DCMAKE_BUILD_TYPE=Debug -DDEBUG -DMIXIT=0 -DNDEBUG -DRELEASE=0 … -D__GXX_EXPERIMENTAL_CXX0X__ -D__STDC_CONSTANT_MACROS
DEP_FILE = CMakeFiles/mynativelib.dir/home/…/mynativelib/MyClass.cpp.o.d
FLAGS = -std=c++14 -fno-stack-protector -ffor-scope -fexceptions -O0 -fno-limit-debug-info \
-fPIC -fno-stack-protector -fpic -ffunction-sections -funwind-tables -no-canonical-prefixes \
-Os -fomit-frame-pointer -fomit-frame-pointer -UNDEBUG -fno-omit-frame-pointer -Ijni -Wformat \
-Wa,--noexecstack -fno-stack-protector -std=c++14
INCLUDES = -I/home/…/Android/Sdk/ndk/18.1.5063045/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/include \
-I../../../../../../../some-custom-include-from-cmake \
-isystem /home/…/Android/Sdk/ndk/18.1.5063045/sources/cxx-stl/llvm-libc++/include
-isystem /home/…/Android/Sdk/ndk/18.1.5063045/sources/cxx-stl/llvm-libc++abi/include
OBJECT_DIR = CMakeFiles/mynativelib.dir
OBJECT_FILE_DIR = CMakeFiles/mynativelib.dir/home/…/mynativelib
I can see that the build command include the some-custom-include-from-cmake include directory, that is added in my CMakeLists.txt file, as well as all the cxx-stl/llvm-libc++ includes that are also added in the CMakeLists.txt file, but the /usr/include/<android-abi> platform include dir is missing.
Even if I use the include_directories(${ANDROID_SYSROOT}/usr/include/aarch64-linux-android) command without the if check, right near where the other include_directories() commands that do make it into the build file, it is still missing from the build file. I even tried to add the -I flag directly using set(CMAKE_CXX_FLAGS) and that didn't cause the required include dir to be listed.
OTOH, if I change the include_directories(${ANDROID_SYSROOT}…) to be something that doesn't start with ${ANDROID_SYSROOT}, or points to a non-existing directory - then whatever I put there does make it to the build.ninja file.
Looks like something is very purposefully removing include directories that are in ${ANDROID_SYSROOT} maybe?

Using OpenCV in Android Studio's NDK (C++) fails with "undefined reference" error

System information
OpenCV 4.3 / 3.4
Linux Ubuntu 16.04
Android Studio (Gradle / Ninja / CMake / clang++)
Detailed description
I'm trying to use OpenCV on Android's NDK.
I have two similar environments - one integrated with OpenCV 4.3 and the other with OpenCV 3.4.
I created an Android C++ app.
For the 4.3 integration I followed this tutorial.
For the 3.4 integration I followed this tutorial.
I have a very basic native-lib.cpp file (see below), which is trying to use cv::imread.
In my code I provide the last trial - which includes the OpenCVLoader.initAsync instance, but I also tried the OpenCVLoader.initDebug way and System.loadLibrary("opencv_java4"), but the error remains.
I tried to build for my SDK version or against libc++, as described in the following:
Android Studio with NDK : link error : undefined reference to 'stderr'
Undefined References Error OpenCv Android with ndk 18 (c++_static)
NDK - problems after GNUSTL has been removed from the NDK (revision r18)
and noticed some other issues, which do not use exactly the same setup (for example, using ndk-build instead of cmake):
OpenCV with Android NDK Undefined References
but failed to solve the issue.
When trying to run the app I get the following errors:
undefined reference to `cv::imread'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
Isn't undefined reference a linker issue?
Did I forget a compiler flag or something?
Steps to reproduce
Follow one of the tutorials (4.3 tutorial or 3.4 tutorial) to integrate OpenCV library into Android Studio.
Create the following simple native-lib.cpp:
#include <jni.h>
#include <string>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
extern "C" JNIEXPORT jstring JNICALL
Java_com_ocv_MainActivity_ocvLoadImage(
JNIEnv *env,
jobject thiz) {
using namespace cv;
using namespace std;
Mat image;
string imageName = "/Pictures/images/image-001.jpg";
image = imread(imageName, IMREAD_COLOR);
std::string returnString = "OpenCV load image: ";
if (! image.empty()){
returnString.append(imageName);
}
return env -> NewStringUTF(returnString.c_str());
}
and call it from this simple MainActivity.java:
package com.ocv;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.util.Log;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
System.loadLibrary("opencv_java4");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
#Override
public void onManagerConnected(int status) {
if (status == LoaderCallbackInterface.SUCCESS) {
TextView textView = findViewById(R.id.sample_text);
String displayString =
textView.getText() +
"\n" + "OpenCV loaded successfully via initAsync" +
"\n" + ocvLoadImage();
textView.setText(displayString);
} else {
super.onManagerConnected(status);
}
}
};
#Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(
OpenCVLoader.OPENCV_VERSION_3_4_0,
this,
mLoaderCallback);
}
public native String ocvLoadImage(String imagePath);
}
NOTES:
When calling OpenCVLoader.initAsync, both the 4.3 and the 3.4 version use the OPENCV_VERSION_3_4_0 flag, since OPENCV_VERSION on 4.3 results in an error. I also tried the OpenCVLoader.initDebug and it produces the same error.
When commenting out the image = imread line in native-lib.cpp, the app runs OK, and returns the string (all cases).
the app's build.gradle:
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions"
abiFilters 'arm64-v8a'
arguments "-DOpenCV_DIR=" + opencvsdk + "/sdk/native/jni"
}
}
...
packagingOptions {
pickFirst 'lib/arm64-v8a/libopencv_java4.so'
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
include_directories(${OpenCV_DIR}/jni/include)
find_package(OpenCV 4.3
REQUIRED
java)
add_library(
native-lib
SHARED
native-lib.cpp )
find_library(
log-lib
log )
target_link_libraries( # Specifies the target library.
native-lib
${OpenCV_LIBRARIES}
${log-lib} )
Error
ERROR:
undefined reference to "cv::imread"
BUILD:
Build command failed.
Error while executing process /path/to/Sdk/cmake/3.10.2.4988404/bin/ninja with arguments {-C /path/to/app/.cxx/cmake/debug/arm64-v8a native-lib}
ninja: Entering directory `/path/to/app/.cxx/cmake/debug/arm64-v8a'
[1/2] Building CXX object CMakeFiles/native-lib.dir/native-lib.cpp.o
[2/2] Linking CXX shared library /path/to/app/build/intermediates/cmake/debug/obj/arm64-v8a/libnative-lib.so
FAILED: /path/to/app/build/intermediates/cmake/debug/obj/arm64-v8a/libnative-lib.so
: && /path/to/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ --target=aarch64-none-linux-android29 --gcc-toolchain=/path/to/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/path/to/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -frtti -fexceptions -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libnative-lib.so -o /path/to/app/build/intermediates/cmake/debug/obj/arm64-v8a/libnative-lib.so CMakeFiles/native-lib.dir/native-lib.cpp.o /path/to/OpenCV-android-sdk/sdk/native/libs/arm64-v8a/libopencv_java4.so /path/to/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/29/liblog.so -ljnigraphics -llog -ldl -lz -latomic -lm && :
MORE
Tried How can I integrate OpenCV 4.0 into a pure C++ Android NDK project? :
CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_ANDROID_STL_TYPE c++_static)
set( OpenCV_DIR "/path/to/opencv-4.3.0-android-sdk/OpenCV-android-sdk/sdk/native/jni" )
find_package(OpenCV
REQUIRED
java)
add_library(native-lib
SHARED
native-lib.cpp )
get_target_property(__src opencv_java IMPORTED_LOCATION_RELEASE )
add_custom_command(TARGET native-lib POST_BUILD COMMAND
${CMAKE_COMMAND} -E copy ${__src} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
include_directories(${OpenCV_INCLUDE_DIRS})
find_library( log-lib
log )
target_link_libraries(
native-lib
opencv_java
${log-lib} )
but still get the same error.

How can I build local/host OS C++ unit tests in Android Studio?

I'm working on a large project with many native modules and I'd like to introduce unit tests of the C++ code that are as simple/fast to run as Java JUnit local (i.e. running on the host OS, not instrumented) tests.
I've followed the official instructions for setting up gtest, but running my external native build results in a linker error:
> Task :app:externalNativeBuildDebug FAILED
Build GoogleTests x86_64
[1/2] Building CXX object CMakeFiles/GoogleTests.dir/googletest_unittests/shared/TautologyTe
sts.cpp.o
[2/2] Linking CXX executable GoogleTests
FAILED: cmd.exe /C "cd . && C:\Users\Jeffrey.Creswell\AppData\Local\Android\Sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=x86_64-none-linux-android21 --gcc-toolchain=C:/Users/Jeffrey.Creswell/AppData/Local/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64 --sysroot=C:/Users/Jeffrey.Creswell/AppData/Local/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/sysroot -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -fno-addrsig -Wa,--noexecstack -Wformat -Werror=format-security -stdlib=libc++ -std=c++14 -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--gc-sections CMakeFiles/GoogleTests.dir/googletest_unittests/shared/TautologyTests.cpp.o CMakeFiles/GoogleTests.dir/googletest_unittests/Tautology.cpp.o -o GoogleTests C:/Users/Jeffrey.Creswell/androidstudio_projects/NativeAndroidSandbox/app/src/main/cpp/googletest_unittests/libs/windows/x86_64/gtestd.lib -latomic -lm && cd ."
C:\Users\Jeffrey.Creswell\androidstudio_projects\NativeAndroidSandbox\app\src\main\cpp\googletest_unittests\shared/TautologyTests.cpp:19: error: undefined reference to 'testing::internal::GetTestTypeId()'
C:\Users\Jeffrey.Creswell\androidstudio_projects\NativeAndroidSandbox\app\src\main\cpp\googletest_unittests\shared/TautologyTests.cpp:19: error: undefined reference to 'testing::internal::MakeAndRegisterTestInfo(char const*, char const*, char const*, char const*, testing::internal::CodeLocation, void const*, void (*)(), void (*)(), testing::internal::TestFactoryBase*)'
...
I built gtestd.lib in Visual Studio and referenced it as a prebuilt in CMakeLists.txt to try to simplify the equation somewhat:
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
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 them 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).
native-lib.cpp)
set(gtest_INC googletest_unittests/include)
include_directories(${gtest_INC})
add_library(gtest STATIC IMPORTED)
set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/googletest_unittests/libs/windows/x86_64/gtestd.lib)
add_executable(GoogleTests
${CMAKE_CURRENT_SOURCE_DIR}/googletest_unittests/shared/TautologyTests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/googletest_unittests/Tautology.cpp)
target_link_libraries(GoogleTests gtest)
# todo: insert add_test() cmake commands once the linker error above is resolved
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries 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 this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
I think the main problem is the argument "--target=x86_64-none-linux-android21" to clang++.exe; it implies compilation of the test executable for Android/Linux, when what I really want is to compile for the host OS (Windows 10). I don't know if this could produce the linker error I'm seeing, but attempting to link a Linux executable to a Windows static library seems like it would fail similarly. How can I tell the Android NDK's clang++ to target the host OS (ideally by modifications to my CMakeLists.txt)? Assuming that's not the problem, is there a known way to get a local (running on host OS) C++ unit test scenario working within Android Studio?
NOTE: I looked at a similar question and the accepted answer appears to work, but generates an Android executable -- I would prefer a situation where I can ideally just hit the green arrow in Android Studio and have my C++ unit tests run automatically on the local machine.
Android Studio does not support host development.
If you want to build your tests against your host and run them there, you'll have to invoke CMake from outside Android Studio (command line would be an option, as would Visual Studio).

Linking external libraries using NDK, Gradle & CMake in Android Studio

I've come back to Android development after a gap and my old ANT based build chain no longer seem to function (that's a separate issue) with the latest SDK, so I'm trying to do things the new way, which is based around gradle and CMake.
I have a number of pre-built static and dynamic 3rd party libraries that my project needs but I've been unable to link these successfully.
From what I can gather, these need to be specified in the 'CMakeLists.txt' file rather than the 'build.gradle' files but I'm new to both systems, so please correct me if I'm wrong.
Here's what I've tried so far:
first, I try to resolve the location of bullet. I've tried variants where I omit the 'lib' the '.a' and the 'armeabi-v7a' (hoping it'd pick up the right CPU variant) but none have worked
find_library(bullet_lib libBullet.a HINTS ${LIBBASE}bullet3/build3/Android/obj/local/armeabi-v7a)
I'm not sure how this differs from the libraries included in target_link_libraries
add_library(bullet_lib STATIC IMPORTED)
this finds the built-in libraries fine but I get linker errors for 'bullet' and other 3rd party libs
target_link_libraries(my_project_name android log EGL GLESv2 bullet_lib)
${LIBBASE} is the base dir for the 3rd party libraries and seems to be OK but, here's another thing: CMake errors don't seem to appear in android studio! I can sort of work out where it's having problems by running cmake . in the folder that contains the 'CMakeLists.txt' file but I'm not quite sure I'm calling that with the correct parameters: whatever Android Studio does with cmake and that file are a black box to me at this time.
The only messages I can see in android studio are linker errors (it doesn't mention CMake errors about not finding the libraries, which is the cause of these linker errors:)
Build command failed.
Error while executing process E:\prog\Android\cmake\3.6.4111459\bin\cmake.exe with arguments {--build E:\prog\anthracite\gradle\AnthracitePlayerAPI21\app\.externalNativeBuild\cmake\debug\x86_64 --target anthracite-lib}
[1/1] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libanthracite-lib.so
FAILED: cmd.exe /C "cd . && E:\prog\Android\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=x86_64-none-linux-android --gcc-toolchain=E:/prog/Android/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64 --sysroot=E:/prog/Android/ndk-bundle/sysroot -fPIC -isystem E:/prog/Android/ndk-bundle/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -fexceptions -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a --sysroot E:/prog/Android/ndk-bundle/platforms/android-21/arch-x86_64 -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,libanthracite-lib.so -o ..\..\..\..\build\intermediates\cmake\debug\obj\x86_64\libanthracite-lib.so #CMakeFiles/anthracite-lib.rsp && cd ."
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:237: error: undefined reference to 'btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache*)'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:240: error: undefined reference to 'btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btDefaultCollisionConstructionInfo const&)'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:242: error: undefined reference to 'btCollisionDispatcher::btCollisionDispatcher(btCollisionConfiguration*)'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:243: error: undefined reference to 'btSequentialImpulseConstraintSolver::btSequentialImpulseConstraintSolver()'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:246: error: undefined reference to 'btDefaultSoftBodySolver::btDefaultSoftBodySolver()'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:247: error: undefined reference to 'btSoftRigidDynamicsWorld::btSoftRigidDynamicsWorld(btDispatcher*, btBroadphaseInterface*, btConstraintSolver*, btCollisionConfiguration*, btSoftBodySolver*)'
E:\prog\anthracite\src/CCmpPhysicsScene3D.cpp:250: error: undefined reference to 'btDiscreteDynamicsWorld::btDiscreteDynamicsWorld(btDispatcher*, btBroadphaseInterface*, btConstraintSolver*, btCollisionConfiguration*)'
E:\prog\anthracite\src/CCmpPhysJointHinge.cpp:117: error: undefined reference to 'btHingeConstraint::btHingeConstraint(btRigidBody&, btVector3 const&, btVector3 const&, bool)'
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
And running 'cmake .' from the command line gives:
-- Selecting Windows SDK version 10.0.16299.0 to target Windows 10.0.17133.
CMake Warning at CMakeLists.txt:447 (message):
resolved libraries:
CMake Warning at CMakeLists.txt:448 (message):
e:/prog/libs/bullet3/build3/Android/obj/local/armeabi-v7a
CMake Warning at CMakeLists.txt:449 (message):
bullet_lib-NOTFOUND
-- Configuring done
-- Generating done
-- Build files have been written to: E:/prog/anthracite/gradle/AnthracitePlayerAPI21/app
although, as I mentioned above, I'm not sure of the veracity of that output as the calling parameters to 'cmake' are likely to be quite different from inside Android Studio. (e.g it's defaulting to a windows build, so I'm not sure if it'd look for '.lib' libraries rather than '.a' or '.so')
Also, I'm using these lines in my 'CMakeLists.txt' file to report the status of the build:
message(WARNING "resolved libraries:")
message(WARNING ${LIBBASE}bullet3/build3/Android/obj/local/armeabi-v7a)
message(WARNING ${bullet_lib})
Anyway, I'm clearly missing something and I've not been able to find any clear guides regarding this. It seems a really simple and obvious thing to do (link a library) but it seems to be a massive pain.
I'd be grateful for any pointers.
You must take care of ABI incompatibility. You are building libanthracite-lib.so for x86_64, so you need the same variant of libBullet.a. If you only need armeabi-v7a, you must specify this in build.gradle, e.g.
android {
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
defaultConfig {
ndk {
abiFilters 'armeabi-v7a'
}
externalNativeBuild {
cmake {
arguments '-DCMAKE_VERBOSE_MAKEFILE=ON'
}
}
}
}
In your E:\prog\anthracite\gradle\AnthracitePlayerAPI21\app\CMakeLists.txt
add_library(bullet_lib STATIC IMPORTED)
set_target_properties(bullet_lib PROPERTIES IMPORTED_LOCATION
${LIBBASE}/bullet3/build3/Android/obj/local/${ANDROID_ABI}/libBullet.a)
target_link_libraries(my_project_name bullet_lib android log EGL GLESv2)
The order of libraries in target_link_libraries may be important, so keep static libs on the left.
I guess you build libBullet.a with ndk-build. You can create a separate library module (let's call in bullet_module) to your AS Project, even if it has no Java files, and point it to the Android.mk:
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
defaultConfig {
ndk {
abiFilters 'armeabi-v7a'
}
externalNativeBuild {
ndkBuild {
targets 'Bullet'
}
}
}
externalNativeBuild {
ndkBuild {
path "${LIBBASE}/bullet3/build3/Android/jni/Android.mk"
}
}
}
Now you can change your CMakeLists.txt to look at results of bullet_module build:
set_target_properties(bullet_lib PROPERTIES IMPORTED_LOCATION
<path/to/bullet_module>/build/intermediates/ndkBuild/debug/obj/local/${ANDROID_ABI}/libBullet.a)

NDK Clang error: undefined reference to 'localeconv'

I am trying to build C++ NDK lib inside Android Studio.I have an external lib called json and the Clang compiler faild on localeconv.
json.hpp:11867: error: undefined reference to 'localeconv'
The locale.h header exists and located inside ndk dir sysroot/usr/include.
My toolchain looks like this:
Gradle: (Showing only the part relevant to NDK)
externalNativeBuild {
cmake {
arguments "-DANDROID_PLATFORM_LEVEL=${platformVersion}",
'-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=gnustl_static'
}
ndk {
abiFilters 'armeabi-v7a'
}
}
Cmake
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11 -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -frtti -fexceptions -Wall")
//'native-lib' is the final .so that's packaged into apk
target_link_libraries(native-lib
OPENAL
FREETYPE
android
EGL
${OPENGL_LIB}
log
m
z
atomic
gnustl_static
)
And here is the linker command line:
[1/1] Linking CXX shared library
........\build\intermediates\cmake\debug\obj\armeabi-v7a\libnative-lib.so
FAILED: cmd.exe /C "cd . &&
D:\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe
--target=armv7-none-linux-androideabi --gcc-toolchain=D:/Android/android-sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64
--sysroot=D:/Android/android-sdk/ndk-bundle/sysroot -fPIC -isystem D:/Android/android-sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi
-D__ANDROID_API__=19 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -frtti -fexceptions -Wall -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a --sysroot D:/Android/android-sdk/ndk-bundle/platforms/android-19/arch-arm
-Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libnative-lib.so
The complete error:
"D:/Android/android-sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/libgnustl_static.a"
&& cd ." D:\XXXXX\XXXXXX\windows....\thirdparty\json/json.hpp:11867:
error: undefined reference to 'localeconv' clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed. :app:externalNativeBuildDebug
FAILED
The target SDK is 21.Minimum SDK is 19.NDK Version: 15.0.4075724
The same code base is compiled fine in Visual Studio Android project which uses the same toolchain.
The answer is - NDK version for SDK 19 doesn't implement the whole C++11 standard in the STL. locale.h header has stubs for localeconv() method, but the library doesn't implement it.The closest Android SDK that implement localeconv() is SDK 21.This is implicitly stated in the header <locale.h>
struct lconv* localeconv(void) __INTRODUCED_IN(21) __VERSIONER_NO_GUARD;
#if __ANDROID_API__ >= 21
locale_t duplocale(locale_t) __INTRODUCED_IN(21);
void freelocale(locale_t) __INTRODUCED_IN(21);
locale_t newlocale(int, const char*, locale_t) __INTRODUCED_IN(21);
#endif /* __ANDROID_API__ >= 21 */
char* setlocale(int, const char*);
#if __ANDROID_API__ >= 21
locale_t uselocale(locale_t) __INTRODUCED_IN(21);
#endif /* __ANDROID_API__ >= 21 */
#define LC_GLOBAL_LOCALE __BIONIC_CAST(reinterpret_cast, locale_t, -1L)
__END_DECLS
#endif /* _LOCALE_H_ */
For me, trying to use Lua 5.4.0, I have to define the API level to 21
Cmake file as:
set(ANDROID_NATIVE_API_LEVEL 21)
I had a similar problem, and unfortunaletly changing API level couldn't work for me --I was working with an old tablet which runs API16. You can try Crystax NDK or you can write an ugly function that mimics the localeconv(). The latter had solved my problem since I was building Lua for Android Terminal Emulator for hobby.

Categories

Resources