I trying to include a shared library through android build system. It named "libmd5b". I already check this library in NDK and it working well. But when I've built android I didn't found my library not in /system/lib and nor in else place. There is my actions step by step:
1) Put sources into ($AndroidSourceFolder)/external/libmd5b/jni
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS := -fPIC
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib
LOCAL_MODULE := md5b
LOCAL_SRC_FILES := md5b.cpp md5.cpp # source files
LOCAL_MODULE_TAGS := optional
# C++ inclusions:
LOCAL_STATIC_LIBRARIES += libstlport_static
LOCAL_C_INCLUDES += external/stlport/stlport bionic/ bionic/libstdc++/include
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_STL:=stlport_static
APP_MODULES := md5b
md5b.cpp
#include <jni.h>
#include <string>
#include <iostream>
#include <fstream>
#include <android/log.h>
#include "md5.h"
using namespace std;
extern "C" {
//Original name changed because we building library system wide visible.
JNIEXPORT jstring JNICALL Md5B
(JNIEnv * env, jobject obj, jstring fpath);
};
JNIEXPORT jstring JNICALL Md5B
(JNIEnv * env, jobject obj, jstring fpath)
{
string strpath = env->GetStringUTFChars(fpath, NULL);
ifstream inFile;
inFile.open(strpath.c_str());
string line;
string strFile;
while (!inFile.eof())
{
getline(inFile, line);
strFile += line;
}
inFile.close();
string md5R = md5(strFile);
char* chmd5R = new char [md5R.length()];
strcpy (chmd5R, md5R.c_str());
return env->NewStringUTF(chmd5R);
}
And there is other library files: md5.cpp and md5.h. This files in pure C++ without any jni preparations. So I think it is no important.
2) Next step is changing ($AndroidSourceFolder)/build/target/product/full.mk to look like this:
PRODUCT_PACKAGES := \
Camera \
libmd5b
$(call inherit-product, $(SRC_TARGET_DIR)/product/full_base_telephony.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/board/generic/device.mk)
# Overrides
PRODUCT_NAME := full
PRODUCT_DEVICE := generic
PRODUCT_BRAND := Android
PRODUCT_MODEL := Full Android on Emulator
3) After all this I launching it to compile:
$source build/envsetup.sh
$lunch full-eng
$make
4) Making libmd5b:
make md5b
<build information>
Install: out/target/product/generic/system/lib/md5b.so
That's it. After end of 'make' I can't found my library. It should be in /system/lib but it is not there. So where is my water library? And why I hasn't got any errors while compile it?
Solved.
There was error in Android.mk file in section named LOCAL_MODULE. Module should be named with lib* preffix:
lib<module name>
Related
What I want to test is the Android NDK JNI called in the following order: C (NDK binary) -> java -> C (shared library). So, I wrote an NDK binary (JNI_src.c) included the shared library (jnitest.so) and ran it on Android. but, at runtime the linker cannot find the shared library jnitest.so used by JNI_src.
08-27 10:29:16.416 1121 1121 F linker : CANNOT LINK EXECUTABLE "/system/bin/JNI_output": library "./obj/local/arm64-v8a/libjnitest.so" not found
The following is the C code and Makefile I wrote (NDK Binary, shared library).
JNI_src.c Code
#include <stdio.h>
#include <android/log.h>
#include <jni.h>
#include <stdlib.h>
extern void shared_func();
int main()
{
printf("hello");
__android_log_print(ANDROID_LOG_INFO, "test", "hello");
// create JNI variable
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs vm_args; // env variables to control invocation
JavaVMOption options[4];
jint res;
jstring jstr;
jclass cls;
jmethodID mid;
jobjectArray args;
vm_args.version = JNI_VERSION_1_2;
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-Djava.class.path=.";
res = JNI_CreateJavaVM(&jvm, (void**) &env, &vm_args);
if(res < 0){
__android_log_print(ANDROID_LOG_INFO, "cnunsrtest", "Can't create Java VM");
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}
cls = (*env)->FindClass(env, "Hello");
if(cls == 0){
__android_log_print(ANDROID_LOG_INFO, "cnunsrtest", "Can't find Hello class");
fprintf(stderr, "Can't find Hello class\n");
exit(1);
}
mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/STring;])V");
if(mid == 0){
__android_log_print(ANDROID_LOG_INFO, "cnunsrtest", "Can't find Hello.main");
fprintf(stderr, "Can't find Hello.main\n");
exit(1);
}
jstr = (*env)->NewStringUTF(env, "Hello, World!");
if(jstr == 0){
__android_log_print(ANDROID_LOG_INFO, "cnunsrtest", "Out of memory1");
fprintf(stderr, "Out of memory1\n");
exit(1);
}
args = (*env)->NewObjectArray(env, 1,
(*env)->FindClass(env, "java/lang/String"), jstr);
if(args == 0){
__android_log_print(ANDROID_LOG_INFO, "cnunsrtest", "Out of memory2");
fprintf(stderr, "Out of memory2\n");
exit(1);
}
(*env)->CallStaticVoidMethod(env, cls, mid, args);
shared_func();
(*jvm)->DestroyJavaVM(jvm);
return 0;
}
jnitest.so (jnitest.c)
#include <jni.h>
#include <stdio.h>
void shared_func()
{
printf("shared func cnunsr");
}
JNIEXPORT void JNICALL java_Hello_jnifunc(JNIEnv *env, jobject obj)
{
printf("Java call cnunsr");
shared_func();
return;
}
Code that built the shared library before make .
aarch64-linux-gnu-gcc -I/home/juno/jdk1.8.0_301/include -I/home/juno/jdk1.8.0_301/include/linux -o libjnitest.so jnitest.c -shared -fPIC
After building the shared library, run the Makefile to get the executable.
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jvm
LOCAL_SRC_FILES := $(SYSROOT)/home/juno/jdk1.8.0_301/jre/lib/aarch64/server/libjvm.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := jnitest
LOCAL_SRC_FILES := $(SYSROOT)/home/juno/Desktop/nkd/libjnitest.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := JNI_output
LOCAL_SRC_FILES := JNI_src.c
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
LOCAL_SHARED_LIBRARIES := jnitest jvm
include $(BUILD_EXECUTABLE)
I copied the executable file and shared library to Android and ran it. But the linker could not find the shared library. I think the cause is incorrect information about the library in the NDK binary. (./obj/local/arm64-v8a/libjnitest.so)
Therefore, readelf was used. (readelf --all JNI_output)
...
Dynamic section at offset 0xdd0 contains 33 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [./obj/local/arm64-v8a/libjnitest.so]
0x0000000000000001 (NEEDED) Shared library: [libjvm.so]
0x0000000000000001 (NEEDED) Shared library: [liblog.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so]
0x0000000000000001 (NEEDED) Shared library: [libm.so]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so]
0x0000000000000001 (NEEDED) Shared library: [libdl.so]
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x0000000000000015 (DEBUG) 0x0
0x0000000000000007 (RELA) 0x650
...
As expected, the dynamic section of libjvm.so is normal, but the dynamic section of libjnitest.so contains an odd path. What part of the Android.mk needs to be modified? I tried setting LD_LIBRARY_PATH to the path where libjnitest.so exists, but the same error occurs.
My goal is open Dicom files and convert thes into cv::Mat to process them with Opencv.
I have compiled dcmtk 3.6.3 on ubuntu 18.4.1 and tried to link it with Qt 5.11.1 with Qt Creator 4.6.2 but failed to do so.
# pro file
QT += core
QT -= gui
TARGET = DcmtkTesting
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
DCMTK_PREFIX = "/home/ismail/dcmtk363"
DCMTK_LIBS_PREFIX=$$DCMTK_PREFIX"/lib"
DCMTK_INCLUDE=$$DCMTK_PREFIX"/include"
INCLUDEPATH+=$$DCMTK_INCLUDE
LIBS += -L$$DCMTK_LIBS_PREFIX
SOURCES += main.cpp
and for the main:
#include
#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/dctk.h"
#include <dcmtk/dcmimgle/dcmimage.h>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
DicomImage *image = new DicomImage("test.dcm");
if (image != NULL)
{
if (image->getStatus() == EIS_Normal)
{
if (image->isMonochrome())
{
image->setMinMaxWindow();
Uint8 *pixelData = (Uint8 *)(image->getOutputData(8 /* bits*/));
if (pixelData != NULL)
{
/* do something useful with the pixel data */
}
}
} else
cout << "Error: cannot load DICOM image (" << DicomImage::getString(image->getStatus()) << ")" << endl;
}
delete image;
return a.exec();
}
and I got this errors:
The error indicates that the linker could not find the symbols (methods) provided by the library. In your .pro file, you pointed the linker to a directory where your library is located, but you forgot to specify which library should be linked.
So you have to modify the line LIBS +=... accordingly, e.g.:
LIBS += -L$$DCMTK_LIBS_PREFIX -ldcmtk
Since I don't know the actual name of the library, I use dcmtk in my example. You may have to adopt it to fit your build environment. Just make sure that you have the -l (lower case L), immediately followed by the library name.
Given
void foo() {
int i = 0;
#ifdef MACRO_A
// custom behaviour
#endif
// program code
}
Is it possible to pass #define MACRO_A to clang++ when compiling to allow the 'custom behavour' statements to come into effect? I cannot find documentation which suggests this is possible in clang++, but it IS possible in other compilers (g++).
The command, thanks to pevasquez's help, is
clang++ -D MACRO_A main.cpp -o main
The function
void foo() {
int i = 0;
#ifdef MACRO_A
// custom behaviour
#endif
// program code
}
will compile with the code in the pre-processor directive section being included.
This will be an addition to my makefiles to create a debug friendly make-chain as well and the production version.
I encountered an error when I am trying to link the Fbx static library (libfbxsdk.a) to a project on Linux using CMake that keeps reporting for undefined references to fbx-related functions. I checked the configuration in the CMakelist and everything looks alright, but the program cannot be compiled statically or dynamically. I really don't have any idea why the static library is not linked properly and appreciate any helps to fix the linking issue. Here is my cmakelist file for static linking:
cmake_minimum_required(VERSION 3.6)
SET(CMAKE_VERBOSE_MAKEFILE ON)
project(FBX_SDK)
add_definitions(-DFBXSDK_NEW_API)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lm -lrt -luuid -lstdc++ -lpthread -ldl -lX11 -std=c++11")
include_directories(${X11_LIBRARIES}
${FBX_SDK_SOURCE_DIR}/fbxsdk-1.2/include/)
link_directories(${X11_LIBRARIES}
${FBX_SDK_SOURCE_DIR}/fbxsdk-1.2/Lib/Linux/Debug_x64/)
set(SOURCE_FILES main.cpp)
add_executable(FBX_SDK ${SOURCE_FILES})
target_link_libraries(FBX_SDK
${FBX_SDK_SOURCE_DIR}/fbxsdk-1.2/Lib/Linux/Debug_x64/libfbxsdk.a)
and my cpp file is as below:
#include <iostream>
#include <fbxsdk.h>
void InitializeSDKObjects(FbxManager* &pManager, FbxScene* &pScene);
int main()
{
std::cout << "Hello, World!" << std::endl;
FbxManager* lSdkManager = NULL;
FbxScene* lScene = NULL;
bool lResult;
InitializeSDKObjects(lSdkManager, lScene);
return 0;
}
void InitializeSDKObjects(FbxManager* &pManager, FbxScene* &pScene)
{
pManager = FbxManager::Create();
if(!pManager)
{
FBXSDK_printf("Error: Unable to create FBX Manager!\n");
exit(1);
}
else FBXSDK_printf("Autodesk FBX SDK version %s\n", pManager->GetVersion());
FbxIOSettings* ios = FbxIOSettings::Create(pManager, IOSROOT);
pManager->SetIOSettings(ios);
FbxString lPath = FbxGetApplicationDirectory();
pManager->LoadPluginsDirectory(lPath.Buffer());
pScene = FbxScene::Create(pManager, "My Scene");
if(!pScene)
{
FBXSDK_printf("Error: Unable to create FBX scene!\n");
exit(1);
}
}
While the include and lib folders of fbx sdk are like this:
I am making an attempt to write an NDK basic app to understand how NDK works. I have a text view and a button in the MainActivity and a library class HelloWorldLib.java which have the static native function helloWorld. I have created the header file copied it and created the ".c" file in the jni folder.
When i am building via ndk-build i am getting the error "no rule to make target" error. I checked lots of posts and answer but nothing worked.
I included a test.c empty file as indicated in the below link and was able to build the project,However, when i ran my app i got the error that " no native implementation found" which is bizzare because i have the implementation.
https://code.google.com/p/android/issues/detail?id=66937
OnClick from where HelloWorldLib is called.
public void onClick(View v) {
// TODO Auto-generated method stub
String inNDK = HelloWorldLib.helloWorld();
tv.setText(inNDK);
}
HelloWorldLib where native is funciton is defined.
public class HelloWorldLib {
public native static String helloWorld();
static{
System.loadLibrary("com.example.androidndk_HelloWorldLib");
}
}
header file created by Javah -jni
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_androidndk_HelloWorldLib */
#ifndef _Included_com_example_androidndk_HelloWorldLib
#define _Included_com_example_androidndk_HelloWorldLib
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_androidndk_HelloWorldLib
* Method: helloWorld
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_androidndk_HelloWorldLib_helloWorld
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
C file copied from .h and then modified.
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <com_example_androidndk_HelloWorldLib.h>
#include <string.h>
extern "C" {
JNIEXPORT jstring JNICALL Java_com_example_androidndk_HelloWorldLib_helloWorld
(JNIEnv *env, jclass clazz){
return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI");
}
Andoid.mk file
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := com.example.androidndk_HelloWorldLib.c
LOCAL_MODULE := com.example.androidndk_HelloWorldLib
include $(BUILD_SHARED_LIBRARY)
The error i am getting in the command prompt is shown below:
D:\Users\gabhatia\Desktop\Android SDK\MyWorkspace\AndroidNDK>ndk-build
make.exe: *** No rule to make target `jni/com.example.androidndk_HelloWorldLib.c
', needed by `obj/local/x86/objs/com.example.androidndk_HelloWorldLib/com.exampl
e.androidndk_HelloWorldLib.o'. Stop.
I am not sure where i am getting wrong but any help will be greatly appreciated.
Thanks.
GB.
Here
LOCAL_SRC_FILES := com.example.androidndk_HelloWorldLib.c
LOCAL_MODULE := com.example.androidndk_HelloWorldLib
change to
FILE_LIST := $(wildcard $(LOCAL_PATH)/*.cpp)
LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%)
Have a try.