I'm trying to add tracing to my C++ project in Android Studio, I'm quite simply following the example in the docs to create a small profiling library in my app: https://developer.android.com/ndk/reference/group/tracing
I get an 'Unused import statement' message on the "#include " line in Android Studio as well as error: use of undeclared identifier 'ATrace_beginSection' compile errors. My CMakeLists.txt file for the library is:
project(profiling)
if(ANDROID)
include_directories(${ANDROID_SYSROOT}/usr/include)
message(STATUS "Including ${ANDROID_SYSROOT}/usr/include")
endif()
set(profiling_SRCS
profiling.cpp
)
set(profiling_HEADERS
profiling.h
)
add_library(profiling STATIC ${profiling_SRCS} ${profiling_HEADERS})
I've checked the cmake log for the "message" entry above, ANDROID_SYSROOT is indeed pointing to the correct location. The library shows up in the app->cpp section in Android Studio, the CMakeLists.txt file shows up in the External Build Files section, I've tried resyncing Gradle, I've tried cleaning and rebuilding, no dice. My targetSdkVersion is set to 27 in my build.gradle.
What am I missing?
Gaaaah. The problem was the minSdkVersion setting in build.gradle - trace.h has this at the top #if __ANDROID_API__ >= 23. For whatever it's worth, I also don't need to include ${ANDROID_SYSROOT}/usr/include in the CmakeLists.txt for this library... Hopefully this will help someone else in the future.
Your cmake file looks not complete. Try to add the path reference point using ${CMAKE_CURRENT_SOURCE_DIR}. E.g.
cmake_minimum_required(VERSION 3.4.1)
project(profiling)
if(ANDROID)
include_directories(${ANDROID_SYSROOT}/usr/include)
message(STATUS "Including ${ANDROID_SYSROOT}/usr/include")
endif()
set(profiling_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/profiling.cpp
)
set(profiling_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/main/cpp/profiling.h
)
add_library(profiling STATIC ${profiling_SRCS} ${profiling_HEADERS})
Related
I have a simple C++ function compiled into a dylib file that I'm trying to run on an Android phone. The function is super simple, it just adds to numbers and returns the result. However, I keep getting this error:
Another exception was thrown: Invalid argument(s): Failed to load dynamic library 'libadd.dylib': dlopen failed: library "libadd.dylib" not found .
I'm really not sure what I'm doing wrong. I've done the following steps:
My Dart implementation:
import 'dart:ffi' as ffi;
import 'dart:io' show Platform, Directory;
import 'package:path/path.dart' as path;
typedef C_ADD = ffi.Int Function(
ffi.Int a, ffi.Int b); // FFI signature of C function
typedef ADD = int Function(int a, int b);
void linkAndCallFunction() {
var libraryPath = path.join(Directory.current.path, "libadd.dylib");
final dylib = ffi.DynamicLibrary.open(libraryPath);
final ADD add = dylib.lookup<ffi.NativeFunction<C_ADD>>("add").asFunction();
final result = add(40, 2);
print(result);
}
I've added these to the build.gradle files:
build.gradle:
buildscript{
ext{
ndkVersion = "25.1.8937393"
}
...
and app/build.gradle:
android {
ndkVersion rootProject.ext.ndkVersion
externalNativeBuild {
cmake {
path "../../lib/CMakeLists.txt"
}
}
This is my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.10.2)
project(add LANGUAGES CXX C)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
add_library(add SHARED ./add.cpp)
and my file structure of the project looks like this:
lib/
- add.cpp
- add.o
- CMakeLists.txt
- libadd.dylib
- main.dart
it also may be worth mentioning that in order to compile add.cpp into a dylib I ran the following commands:
g++ -c add.cpp
ar rvs libadd.dylib add.o
and if you're wondering, add.cpp looks like this:
#define EXPORT extern "C" __attribute__((visibility("default")))
__attribute__((used))
EXPORT
int add(int a, int b){
return a + b;
}
Where is this error coming from? am I compiling to a dylib incorrectly?
The answer to this problem was relatively simple, it just stemmed from my lack of knowledge on how Android actually compiles to a static library. Hopefully it helps someone else who is trying to understand how to setup external C++ code in a flutter program.
The static library is generated automatically and is set up in CMakeLists.txt.
Firstly, I moved all the C++ files into the android folder. Then, I set up CMakeLists.txt like this:
cmake_minimum_required(VERSION 3.10.2)
add_library( add // library name, will create libadd.so
SHARED
add.cpp
)
The problem before was that I was trying to manually compile the file myself, when I should have been letting CMakeLists do it instead. According to the android documentation:
"The convention CMake uses to name the file of your library is as follows:
liblibrary-name.so
For example, if you specify "native-lib" as the name of your shared library in the build script, CMake creates a file named libnative-lib.so. "
https://developer.android.com/studio/projects/configure-cmake
So when I run the program, the static library is created automatically and placed in the correct place. Then, the Dart FFI can find it with the DynamicLibrary.open() function. In this case, CMakeLists will generate a file called libadd.so, and I can callDynamicLibrary.open('libadd.so') and the program works.
I have Qt 6.3 CMake-project that contains two subdirectories "app" and "service", i want include Android service .so library into result APK.
With qmake-project i can achieve this like that at app.pri:
contains(ANDROID_TARGET_ARCH, arm64-v8a) {
release: ANDROID_EXTRA_LIBS = $$OUT_PWD/../service/libservice_arm64-v8a.so
debug: ANDROID_EXTRA_LIBS = $$OUT_PWD/../service/libservice_arm64-v8a.so
}
with CMake i tried to set(QT_ANDROID_EXTRA_LIBS C:/workspace/build-test-Android_Qt_6_3_0_Clang_arm64_v8a-Debug/service/libservice_arm64-v8a.so)
at app->CMakeLists.txt and it has no effect.
Found that QT_ANDROID_EXTRA_LIBS is 'target property' and should be set via set_target_properties() then it adds .so into result.
set_target_properties(project_name PROPERTIES
QT_ANDROID_EXTRA_LIBS ${CMAKE_CURRENT_BINARY_DIR}/../service/libservice_${ANDROID_ABI}.so)
I am trying to move my libs into product partition, and so that I have done all required changes and removed libandroid_runtime and libnativehelper because both are NON-ndk libs (both are using private apis). I was able to fix all the build time errors in android 30. But I am getting issue while building in Android S.
My 2 libs are using header_libs: ["jni_headers"], And when I try a full build or any app build I am getting below error for both libs -
FAILED: out/soong/.intermediates/mylib_path/android_product.S_arm_armv7-a-neon_cortex-a9_shared/mylib.so.toc
echo "module mylib missing dependencies: jni_headers{os:android,image:product.S,arch:arm_armv7-a-neon_cortex-a9,sdk:}" && false
module mylib missing dependencies: jni_headers{os:android,image:product.S,arch:arm_armv7-a-neon_cortex-a9,sdk:}
And if I remove this line I am getting missing #include <jni.h> header file error. So for the alternate purpose, I included jni.h file in my source code and now it's building perfectly. But I think this is not the right way to fix this.
Could you please look into this issue?
Thank you.
I encountered a similar issue and was able to solve it by adding jni_headers as a header lib.
Here is a copy of my Android.bp:
cc_library {
name: "libpinenote",
host_supported: false,
product_specific: true,
srcs: ["cpp/*.cpp"],
shared_libs: ["liblog"],
header_libs: ["jni_headers"],
cflags: [
"-Wno-error-unused-parameter",
"-fexceptions",
],
}
I have a library in C called mylib in the folder
jniLibs/your_architecture/mylib.so
In Java, to load the library, you just have to type that code in your source:
static {
System.loadLibrary("mylib");
}
But how can you load the library in a native C code (in Android Studio) ?
I add that the library don't use the JNI conventions, it's a normal shared library.
If this can help someone, here how to load a library in native code c/c++ :
1 - to avoid java.lang.UnsatisfiedLinkError: dlopen failed: add this to the build.gradle into android block :
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
Assuming that your lib files are in
src/main/jniLibs/{Architecture}/
( depending where is your jniLibs folder, in my case it is located at app/src/main/ but the most time it is in app/)
2 - In your CMakeList, add you library as SHARED and IMPORTED by adding the following block :
add_library(mylib SHARED
IMPORTED
)
3 - Add target properties to locate you lib mylib.so by adding the following block :
set_target_properties( mylib PROPERTIES
IMPORTED_LOCATION
${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/mylib.so
)
We back forward (/../) here because we concidere that CMakeLists.txt is in
src/main/cpp/
Otherwise, the most time it is in app/ folder, in this case, we don't need to back forward.
So we have to back to main/ before going into jniLibs/
4 - Add you lib mylib to your target link libraries :
target_link_libraries(native-library-jni
..
..
mylib
..
..
)
5 - Finally, to call methods of your lib mylib.so, you have to create/copy-past the header containing these methods signatures and include it in your source file : #include "mylib.h"
You can now call your methods [namespace::]method(args...)
Extra links :
PROJECT_SOURCE_DIR
CMAKE_SOURCE_DIR
Q : Are CMAKE_SOURCE_DIR and PROJECT_SOURCE_DIR the same in CMake?
It seems that sbt-android is ignoring the presence of the RenderScript files and is not generating the ScriptC_xxx java classes that are normally generated by gradle builds/Android Studio [UPDATE: this is false, se the update note below]. Because of this issue, the sbt-android build is failing because to use the scripts we need to reference the generated ScriptC_xxx classes, which gives the following error when building:
[error] apackage/YYYClass.java:55: cannot find symbol
[error] symbol: class ScriptC_xxx
[error] location: class apackage.YYYClass
[error] ScriptC_xxx xxxScript = new ScriptC_xxx(rs);
The generated .sbt file from the existing project (which compiles normally by gradle) has the apparent necessary configuration for RenderScript, generated from the build.gradle file:
rsTargetApi in Android := "18",
rsSupportMode in Android := rsSupportMode.value || true
What I am missing to be able to compile renderscript-containing android projects with sbt-android ?
UPDATE: I realized that the java classes for the scripts are being generated correctly, but somehow the classes that use those generated classes cannot find them, so maybe I have a classpath configuration problem.
This is the current file structure:
./asubmodule/src/main/rs/xxx.rs
(using package declaration #pragma rs java_package_name(apackage.scripts))
./asubmodle/src/main/java/apackage/YYYClass.java
./asubmodule/target/android/generated/source/android/support/v7/appcompat/R.java
./asubmodule/target/android/generated/source/apackage/scripts/ScriptC_xxx.java
Unfortunately, it seems com.android.builder.core.AndroidBuilder no longer generates .d files for processed renderscript sources. Bypassing AndroidBuilder to use com.android.sdklib.build.RenderScriptProcessor in sbt-android could restore the .d files that are required to determine the generated files. But that would be a solution for a future version of sbt-android.
To work around your problem for now, you can add the following into your build.sbt:
sourceGenerators in Compile += Def.task {
implicit output = outputLayout.value
val layout = projectLayout.value
(layout.generatedSrc ** "ScriptC_*.java").get ++ (layout.generatedSrc ** "*BitCode.java").get
}.taskValue
Since it sounds like you're using sbt-android-gradle you can just create a new file build.sbt and throw the above in (do not edit the 00-gradle-generated.sbt)
Update: this will be fixed in the next version of sbt-android https://github.com/scala-android/sbt-android/commit/ec09a55233aabd50e7df0085b10c567e38b616d3