I'm trying to use JNI with Bazel (0.12.0):
WORKSPACE file:
android_ndk_repository(
name = "androidndk",
)
libs/hello_lib_c/BUILD:
cc_library(
name = "hello_lib_c",
srcs = ["src/hello.c"],
visibility = ["//visibility:public"],
)
libs/hello_lib_c/src/hello.c:
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_eu_tamere_bazel_HelloJNI_hello(JNIEnv *env, jclass clazz) {
return (*env)->NewStringUTF(env, "Hello from JNI ");
}
libs/hello_lib_java/BUILD:
android_library(
name = "hello_lib_java",
srcs = glob(["src/eu/tamere/bazel/**"]),
deps = ["//libs/hello_lib_c"],
visibility = ["//visibility:public"],
)
When building the Java lib, the jni.h header file is not found. Any idea on how to declare the dependency?
$ bazel build //libs/hello_lib_java
INFO: Analysed target //libs/hello_lib_java:hello_lib_java (22 packages loaded).
INFO: Found 1 target...
ERROR: /path/to/project/libs/hello_lib_c/BUILD:1:1: C++ compilation of rule '//libs/hello_lib_c:hello_lib_c' failed (Exit 1)
libs/hello_lib_c/src/hello.c:1:10: fatal error: jni.h: No such file or directory
#include <jni.h>
^~~~~~~
compilation terminated.
Target //libs/hello_lib_java:hello_lib_java failed to build
Use --verbose_failures to see the command lines of failed build steps.
I've tried to add hdrs = ["#androidndk//:jni_header"], to the cc_library definition but it does now work either. I've also tried to explicitly set the path for the Android NDK in the WORKSPACEbut it does not change.
The android example on the official repo does not specify where to find the jni lib.
It seems that using JNI inside an android_library (i.e., .aar) is not possible at the moment without some tricks. Only android_binary (i.e., .apk) will link the jni lib.
From https://github.com/bazelbuild/bazel/issues/348 :
android_library .aar output does not currently support bundling native libraries. This is a known deficiency that I believe #dkelmer has plans to work on.
aj-michael has a repo with a workaround:
https://github.com/aj-michael/aar_with_jni
Related
I am working on Android native project using C++ code built using CMake. Currently my app is running fine and native lib(.so) is successfully loaded using System.loadLibrary().
But I want to test JUnit tests on my mac in Android Studio. When running tests on mac, It throws error
myapp.dylib not found.
Here is my CMakeLists.txt :
cmake_minimum_required(VERSION 3.18.1)
# Declares and names the project.
project("myapplication")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
add_library( # Sets the name of the library.
myapplication
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp
native2.cpp)
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)
Here is my cpp file:
#include <jni.h>
#include <string>
#include "header.h"
#include<android/log.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
return env->NewStringUTF(hello.c_str());
}
To build .dylib when running cmake from command line, I get other errors like jni not found and liblog(android log library) not found.
Is there a way that I can build .dylib for mac OS in such a way that it can resolve android specific dependencies like jni and log library?
I want to implement baresip lib into my Android project using NDK.
I've found up-to-date "bare bones" demo-project in HERE. As in readme I've created some native libs from another repo and placed in "distribution" folder. Project is compiling, installing, working fine. Comparing to Android native sip implementation this lib is just awesome, use it, forget about permission.USE_SIP, its rubish.
Now I want to import baresip into my project, but without Java/Kotlin files, planning to build own. So my steps:
Added externalNativeBuild entries to build.gradle
Copied cpp and distribution folders to proper places in my structure
Invalidate cache and restart
And got exception:
Build command failed.
Error while executing process C:\Android\sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build C:\Android\projects\MyApplication\app.cxx\cmake\debug\armeabi-v7a --target baresip}
[1/2] Building C object CMakeFiles/baresip.dir/baresip.c.o
[2/2] Linking C shared library C:\Android\projects\MyApplication\app\build\intermediates\cmake\debug\obj\armeabi-v7a\libbaresip.so
FAILED: cmd.exe /C "..."
next some duplicated lines like:
src/video.c:331: error: undefined reference to 'atof'
src/main/main.c:944: error: undefined reference to 'signal'
src/main/main.c:775: error: undefined reference to '__FD_ISSET_chk'
src/main/main.c:690: error: undefined reference to '__FD_SET_chk'
C:/Android/projects/MyApplication/app/src/main/cpp/../../../../distribution/openssl/lib/armeabi-v7a/libcrypto.a(armcap.o):armcap.c:function OPENSSL_cpuid_setup: error: undefined reference to 'sigfillset'
and ends with
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
note app/src/main/cpp/../../../../distribution/ files path, as declared in CMakeLists:
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../distribution)
For me it looks like not-visible files for compiler, but when I add/remove some/any ../ error changes to clearly suggesting wrong path. besides same path and hierarchy is in sample project
I've tried to strip out baresip.c file, but its crashing with just logging OnLoad call...
#include <string.h>
#include <pthread.h>
#include <jni.h>
#include <android/log.h>
#include <stdlib.h>
#include <re.h>
#include <baresip.h>
#define LOGD(...) \
if (log_level_get() < LEVEL_INFO) ((void)__android_log_print(ANDROID_LOG_DEBUG, "Baresip Lib", __VA_ARGS__))
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
LOGD("at JNI_OnLoad\n");
return JNI_VERSION_1_6;
}
crash still occurs, but when I comment out if (log_level_get() < LEVEL_INFO) call my project is building and install just fine... log_level_get() comes from baresip.h, which is #included, libbaresip.a files (per abi) present, so why is libbaresip.so missing, why it isn't generating? what lines are present in sample project which makes it to build and work?
(yep, I'm pretty weak in native, lost some support from colleagues due to coronavirus...)
turns out it was a bit hidden, but nothing tough... target/compile SDK version should be at least 21 for this lib, I had 19, thats why ndk wasn't compiling properly...
Working on an Android NDK project. The project is using CMake to build the C++ libraries.
The library has the following structue -
Main Library
main.cpp
CMakeLists.txt
hello (sub library)/
CMakeLists.txt
include/
hello.h
src/
hello.c
world (sub library)/
CMakeLists.txt
include/
world.h
src/
world.c
The contents are the following:
main.cpp
#include <jni.h>
#include <string>
#include <hello.h>
#include <world.h>
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_test_myapplication_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string str = hello() + world();
return env->NewStringUTF(str.c_str());
}
CMakeLists.txt for main.cpp
cmake_minimum_required(VERSION 3.4.1)
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).
src/main/cpp/native-lib.cpp )
add_subdirectory(src/main/cpp/hello)
include_directories(src/main/cpp/hello)
add_subdirectory(src/main/cpp/world)
include_directories(src/main/cpp/world)
target_link_libraries( # Specifies the target library.
native-lib
hello
world)
world.h
#include <string>
std::string world();
world.c
#include "world.h"
std::string world() {
return std::string("world");
}
CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project (world)
add_definitions(/DVERSION="0.4.0")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os")
include_directories(include/)
set(SOURCES
src/world.c
include/world.h
)
add_library(world STATIC IMPORTED
${SOURCES}
)
target_include_directories(world PUBLIC ./)
The content is the same for the "hello" library as the only difference is the output returned from hello's function.
Now, my experience with CMake is close to non-existent and I can't get this to work. I'm constantly getting errors upon building it. Latest error is the following -
CMake Error at src/main/cpp/hello/CMakeLists.txt:19
(target_include_directories): Cannot specify include directories for
imported target "hello". CMake Error at
src/main/cpp/world/CMakeLists.txt:19 (target_include_directories):
Cannot specify include directories for imported target "world".
I just can't find a way to compile all of it into a simple library that will be used in the app. Sometimes I get " not found", sometimes it can't find the header files and etc.
I'd appericiate if someone will be able to post a simple structure and CMake of the correct way of doing so as I'm lost.
In the actual project I try to use libmicrohttpd, but again, can't make it work. I've tried using CentOS's libraries but Android Studio seems to use the system's libraries which causes things to get messed up. This is the reason for which I download the library and try to compile it via Android Studio.
So, again, if anyone will be able to find a way to compile all of the 3 libraries together into a single library (main) which connected the other 2 (hello, world), I'd greatly appericiate it.
Much appericiated.
I'm building a native library for my Android application with bazel.
I'd like to use some OpenSSL functions on it like this:
#include <jni.h>
#include <openssl/aes.h>
...
AES_encrypt(in, out, key);
How to add the openssl library to bazel build ?
Subsidiary question: which archive I should use ?
openssl-1.1.0c.tar.gz
openssl-1.0.2j.tar.gz
openssl-1.0.1u.tar.gz
openssl-fips-2.0.13.tar.gz
openssl-fips-ecp-2.0.13.tar.gz
What I've tried
I've downloaded the openssl-1.0.2j archive. and added a cc_library entry to my BUILD file.
cc_library(
name = "openssl",
srcs = glob([
"openssl-1.0.2j/crypto/**/*.h",
"openssl-1.0.2j/crypto/**/*.c"
]),
includes = [
"openssl-1.0.2j",
"openssl-1.0.2j/crypto/",
],
visibility = ["//visibility:public"],
)
I've this error:
openssl-1.0.2j/crypto/dh/p512.c:60:24: fatal error: openssl/bn.h: No such file or directory
#include <openssl/bn.h>
But I don't understand why this code is trying to include a file from openssl while it's in openssl-1.0.2j/crypto/
With openssl-1.1.0c
openssl-1.1.0c/include/openssl/e_os2.h:13:34: fatal error: openssl/opensslconf.h: No such file or directory
# include <openssl/opensslconf.h>
Even if I run the Configure command, no opensslconf.h file is generated.
Based on #Ulf Adams' answer, I gave up trying to compile OpenSSL with bazel. I used BoringSSL instead.
BoringSSLis a fork of OpenSSL, and can easily be incorporated to a bazel project by doing:
git_repository(
name = "boringssl",
commit = "_some commit_",
remote = "https://boringssl.googlesource.com/boringssl",
)
I am playing with android ndk. I am using Window Vista with cygwin (latest version). I compiled and launched the hello world jni sample on my phone. It is working. The code is (is a .cpp file):
#include <string.h>
#include <jni.h>
extern "C" {
JNIEXPORT jstring JNICALL Java_org_android_helloworld_HelloworldActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis);
};
jstring Java_org_android_helloworld_HelloworldActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis)
{
return env->NewStringUTF("Hello from native code!");
}
I wanted to add some modifications, just to play with it a bit:
#include <algorithm>
and then, in the function above, i added:
int a;
a=std::min<int>(10, 5);
but the compiler says that it cannot find the file 'algorithm' and that min() is not part of std.
After a bit of searching, i have found that the android ndk has a gnu-libstdc++ directory with all the std files needed. Reading the NDK docs, i have learned that usint std::* should work without any modification to the code (if one include the proper header files). But it seems that gcc on cygwin is not able to find the needed files.
What are the steps to do in order to be able to use std and stl within a .cpp file in an android ndk app?
From NDK r5's docs/CPLUSPLUS-SUPPORT.html:
By default, the headers and libraries for the minimal C++ runtime system
library (/system/lib/libstdc++.so) are used when building C++ sources.
You can however select a different implementation by setting the variable
APP_STL to something else in your Application.mk, for example:
APP_STL := stlport_static
To select the static STLport implementation provided with this NDK.
Value APP_STL values are the following:
system -> Use the default minimal C++ runtime library.
stlport_static -> Use STLport built as a static library.
stlport_shared -> Use STLport built as a shared library.
gnustl_static -> Use GNU libstdc++ as a static library.
Which NDK are you using? Have you tried compiling one of the sample applications that utilize the STL such as test-libstdc++?