How does APP_OPTIM manifest in code? - android-ndk

In Application.mk you can set:
APP_OPTIM := release
APP_OPTIM := debug
How can I test for release/debug build in C++?
I'm assuming there are defines so I've tried this, but only "NOT" messages are logged:
#ifdef RELEASE
LOGV("RELEASE");
#else
LOGV("NOT RELEASE");
#endif
#ifdef DEBUG
LOGV("DEBUG");
#else
LOGV("NOT DEBUG");
#endif

In android-ndk-r8b/build/core/add-application.mk we read:
ifeq ($(APP_OPTIM),debug)
APP_CFLAGS := -O0 -g $(APP_CFLAGS)
else
APP_CFLAGS := -O2 -DNDEBUG -g $(APP_CFLAGS)
endif
So, to answer your question: in NDK r8b (the latest for today) you can check
#ifdef NDEBUG
// this is "release"
#else
// this is "debug"
#endif
But you can add any other compilation flags through your Android.mk or Application.mk depending on $(APP_OPTIM), if you want.

Related

How to link .so library properly in C++?

I have project structure like this,
a.pb.h --- includes --> protobuf.h
b.grpc.pb.h --- includes --> a.pb.h & grpcpp.h
Also there are a.pb.cc and b.grpc.cc files.
A C++ wrapper with extern C which is wrapper.cc and wrapper.h which includes b.grpc.pb.h and grpcpp.h.
The function inside extern C is char* helloWorld(const char*, const char*, const char*);
Creating .o of a.pb.h and b.grpc.pb.h:
g++ -fpic -std=c++11 `pkg-config --cflags protobuf grpc` -c -o a.pb.o a.pb.cc
g++ -fpic -std=c++11 `pkg-config --cflags protobuf grpc` -c -o b.grpc.pb.o b.grpc.pb.cc
Steps to create libcombined.so:
The grpc and protobuf so are already provided under /usr/local/lib.
First created .so of a.pb.o and b.grpc.pb.o to compile wrapper file as:
g++ -shared -o libcombined.so *.o
Compiled wrapper as:
g++ -fpic wrapper.cc -l:./libcombined.so -c -o wrapper.o -std=c++11
.so of a.pb.o, b.grpc.pb.o and wrapper.o as libcombined.so:
g++ -shared -o libcombinedwrapper.so *.o
Compiled main.c as:
gcc main.c -l:./libcombinedwrapper.so -o main -ldl
I am calling helloWorld from my main.c file which is:
#include <stdio.h>
#include <dlfcn.h>
int main(){
char* (*fn)(const char*,const char*,const char*);
void *handle = dlopen("path_to/libcombined.so",RTLD_NOW);
if(handle==NULL){
fprintf(stderr, "Error: %s\n", dlerror());
}
fn = (char* (*)(const char*,const char*,const char*))dlsym(handle, "helloWorld");
if (!fn) {
/* no such symbol */
fprintf(stderr, "Error: %s\n", dlerror());
dlclose(handle);
return 0;
}
char* msg = fn("asd","asdas","asdasd");
printf("%s",msg);
return 0;
}
Error after executing: ./main
Error: path_to/libcombinedwrapper.so: undefined symbol: _ZN6google8protobuf2io20ZeroCopyOutputStream15WriteAliasedRawEPKvi
Error: ./main: undefined symbol: helloWorld
Segmentation fault (core dumped)
The first above error is from symbol from protobuf.h file.
Can someone please suggest what I am doing wrong while linking or is there something I am doing wrong in main.c file?
g++ -shared -o libcombined.so *.o
You need to also link in all dependencies of the objects (libgrpc here).
You can add -Wl,--no-allow-shlib-undefined to verify that libcombined.so is linking everything it needs.
P.S. To avoid core dump, you should exit or return once dlopen fails.
P.P.S. It is generally a very bad idea(TM) to link *.o. Use proper Makefile to avoid unnecessary compilations and explicitly list objects that you are intending to put into libcombined.so.

Building pjSip 2.5 - unable to undefined reference to 'pj_jni_jvm'

Trying to build pjSIP from sources for Android, using following guide - https://trac.pjsip.org/repos/wiki/Getting-Started/Android
Checkout sources of pjsip (2.5)
export ANDROID_NDK_ROOT=/home/dev/android/android-ndk-r9b
export TARGET_ABI=armeabi
export APP_PLATFORM=android-13
./configure-android --use-ndk-cflags --disable-video --disable-l16-codec --disable-gsm-codec --disable-g722-codec --disable-g7221-codec --disable-ssl --disable-ilbc-codec --disable-tls
configuration is completed successfully.
make dep && make clean && make
And I got following error - >
../src/pj/guid_android.c:43: error: undefined reference to 'pj_jni_jvm'
../src/pj/guid_android.c:117: error: undefined reference to 'pj_jni_jvm'
The command invoked by linked which leads to this error
/home/dev/android/android-ndk-r9b/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc -o ../bin/pjlib-test-arm-unknown-linux-androideabi \
output/pjlib-test-arm-unknown-linux-androideabi/main.o output/pjlib-test-arm-unknown-linux-androideabi/activesock.o output/pjlib-test-arm-unknown-linux-androideabi/atomic.o output/pjlib-test-arm-unknown-linux-androideabi/echo_clt.o output/pjlib-test-arm-unknown-linux-androideabi/errno.o output/pjlib-test-arm-unknown-linux-androideabi/exception.o output/pjlib-test-arm-unknown-linux-androideabi/fifobuf.o output/pjlib-test-arm-unknown-linux-androideabi/file.o output/pjlib-test-arm-unknown-linux-androideabi/hash_test.o output/pjlib-test-arm-unknown-linux-androideabi/ioq_perf.o output/pjlib-test-arm-unknown-linux-androideabi/ioq_udp.o output/pjlib-test-arm-unknown-linux-androideabi/ioq_unreg.o output/pjlib-test-arm-unknown-linux-androideabi/ioq_tcp.o output/pjlib-test-arm-unknown-linux-androideabi/list.o output/pjlib-test-arm-unknown-linux-androideabi/mutex.o output/pjlib-test-arm-unknown-linux-androideabi/os.o output/pjlib-test-arm-unknown-linux-androideabi/pool.o output/pjlib-test-arm-unknown-linux-androideabi/pool_perf.o output/pjlib-test-arm-unknown-linux-androideabi/rand.o output/pjlib-test-arm-unknown-linux-androideabi/rbtree.o output/pjlib-test-arm-unknown-linux-androideabi/select.o output/pjlib-test-arm-unknown-linux-androideabi/sleep.o output/pjlib-test-arm-unknown-linux-androideabi/sock.o output/pjlib-test-arm-unknown-linux-androideabi/sock_perf.o output/pjlib-test-arm-unknown-linux-androideabi/ssl_sock.o output/pjlib-test-arm-unknown-linux-androideabi/string.o output/pjlib-test-arm-unknown-linux-androideabi/test.o output/pjlib-test-arm-unknown-linux-androideabi/thread.o output/pjlib-test-arm-unknown-linux-androideabi/timer.o output/pjlib-test-arm-unknown-linux-androideabi/timestamp.o output/pjlib-test-arm-unknown-linux-androideabi/udp_echo_srv_sync.o output/pjlib-test-arm-unknown-linux-androideabi/udp_echo_srv_ioqueue.o output/pjlib-test-arm-unknown-linux-androideabi/util.o -lpj-arm-unknown-linux-androideabi -nostdlib -L/home/dev/android/android-ndk-r9b/platforms/android-13/arch-arm/usr/lib -L/home/dev/android/android-ndk-r9b/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi/ -lm /home/dev/android/android-ndk-r9b/platforms/android-13/arch-arm/usr/lib/crtbegin_so.o -lgnustl_static -lc -lgcc -ldl -lOpenSLES -llog -L/home/dev/android/pjproject-2.5/pjlib/lib -L/home/dev/android/pjproject-2.5/pjlib-util/lib -L/home/dev/android/pjproject-2.5/pjnath/lib -L/home/dev/android/pjproject-2.5/pjmedia/lib -L/home/dev/android/pjproject-2.5/pjsip/lib -L/home/dev/android/pjproject-2.5/third_party/lib -nostdlib -L/home/dev/android/android-ndk-r9b/platforms/android-13/arch-arm/usr/lib -L/home/dev/android/android-ndk-r9b/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi/
Code of guid_androind.c
#include <pj/guid.h>
#include <pj/log.h>
#include <pj/string.h>
#include <jni.h>
extern JavaVM *pj_jni_jvm;
static pj_bool_t attach_jvm(JNIEnv **jni_env)
{
if ((*pj_jni_jvm)->GetEnv(pj_jni_jvm, (void **)jni_env,
JNI_VERSION_1_4) < 0)
{
if ((*pj_jni_jvm)->AttachCurrentThread(pj_jni_jvm, jni_env, NULL) < 0)
{
jni_env = NULL;
return PJ_FALSE;
}
return PJ_TRUE;
}
return PJ_FALSE;
}
#define detach_jvm(attached) \
if (attached) \
(*pj_jni_jvm)->DetachCurrentThread(pj_jni_jvm);
Struggling with this error for whole day, any clue is highly appreciated. Meanwhile I'm able to build version 2.3 without any errors, but not 2.5
I believe you missed a step.
https://trac.pjsip.org/repos/wiki/Getting-Started/Android#BuildPreparation
Set your config_site.h to the following:
/* Activate Android specific settings in the 'config_site_sample.h' */
#define PJ_CONFIG_ANDROID 1
#include <pj/config_site_sample.h>

Android NDK - Android studio gradle undefined reference to __android_log_write

I am trying to debug a JNI C function by inserting log messages, but I can't get it to work. To start with I am just trying to modify the hello-jni example that comes with Android Studio. This is the modified code:
#include <string.h>
#include <jni.h>
#include <android/log.h>
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a/NEON (hard-float)"
#else
#define ABI "armeabi-v7a/NEON"
#endif
#else
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a (hard-float)"
#else
#define ABI "armeabi-v7a"
#endif
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__x86_64__)
#define ABI "x86_64"
#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */
#define ABI "mips64"
#elif defined(__mips__)
#define ABI "mips"
#elif defined(__aarch64__)
#define ABI "arm64-v8a"
#else
#define ABI "unknown"
#endif
__android_log_write(ANDROID_LOG_ERROR, "TEST_TAG", "Error here");
return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI ".");
}
And this is my Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_LDFLAGS := -llog
include $(BUILD_SHARED_LIBRARY)
When I use the ndk-build script the libhello-jni.so files get built no problem. When I try to build the project in Android Studio I get the following gradle error message
Information:Gradle tasks [:app:assembleDebug]
:app:preBuild
:app:compileDebugNdk
C:\Android\projects\hello-jni\app\build\intermediates\ndk\debug\obj/local/arm64-v8a/objs/hello-jni/C_\Android\projects\hello-jni\app\src\main\jni\hello-jni.o: In function `Java_com_example_hellojni_HelloJni_stringFromJNI':
hello-jni.c:(.text.Java_com_example_hellojni_HelloJni_stringFromJNI+0x24): undefined reference to `__android_log_write'
Error:error: ld returned 1 exit status
make.exe: *** [C:\Android\projects\hello-jni\app\build\intermediates\ndk\debug\obj/local/arm64-v8a/libhello-jni.so] Error 1
Error:Execution failed for task ':app:compileDebugNdk'.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
C:\Android\android-ndk-r10c\ndk-build.cmd NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=C:\Android\projects\hello-jni\app\build\intermediates\ndk\debug\Android.mk APP_PLATFORM=android-19 NDK_OUT=C:\Android\projects\hello-jni\app\build\intermediates\ndk\debug\obj NDK_LIBS_OUT=C:\Android\projects\hello-jni\app\build\intermediates\ndk\debug\lib APP_ABI=all
Error Code:
2
Output:
C:\Android\projects\hello-jni\app\build\intermediates\ndk\debug\obj/local/arm64-v8a/objs/hello-jni/C_\Android\projects\hello-jni\app\src\main\jni\hello-jni.o: In function `Java_com_example_hellojni_HelloJni_stringFromJNI':
hello-jni.c:(.text.Java_com_example_hellojni_HelloJni_stringFromJNI+0x24): undefined reference to `__android_log_write'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [C:\Android\projects\hello-jni\app\build\intermediates\ndk\debug\obj/local/arm64-v8a/libhello-jni.so] Error 1
Information:BUILD FAILED
Information:Total time: 3.297 secs
Information:2 errors
Information:0 warnings
Information:See complete output in console
I've tried the suggestions given in this question, but I still get the same error: What is the Log API to call from an Android JNI program?
What am I doing wrong?
I'm using Android Studio 0.8.9 and NDK r10c.
I found an answer after a bit more searching.
If I build the .so files using the ndk-build script on the command line and add
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir 'src/main/libs'
}
into my build.gradle file so gradle doesn't try to build the .so files it all then works. Looks like a problem with Android Studio-Gradle-NDK integration?
I found the answer here https://stackoverflow.com/a/21111458/4182796
Ugly workaround is to remove function call and rebuild sources just add this after includes :
#if 1
#undef __android_log_print
#define __android_log_print(...) {}
#endif

Kernel module with multiple files - unknown symbol

Hello stackoverflowers :)
For the last several hours I've been trying to compile+load a multiple file module. The compilation emits a strange warning and the module fails to load. Here are the module, Makefile, compilation output and dmesg.
header:
// header.h
#ifndef _HEADER_H
#define _HEADER_H
void do_module_func(void);
void do_other_func(void);
#endif
'main' module file:
//mymodule.c
#include <linux/module.h>
#include <linux/kernel.h>
#include "header.h"
void do_module_func(void)
{
printk(KERN_INFO "module_func\n");
}
static int mymodule_init(void)
{
printk(KERN_INFO "Hello world\n");
do_other_func();
return 0;
}
module_init(mymodule_init);
static void mymodule_exit(void)
{
printk(KERN_INFO "Goodbye, cruel world\n");
}
module_exit(mymodule_exit);
MODULE_LICENSE("GPL")
other c file, which calls do_module_func() that sits in the 'main' module
//other_file.c
#include "header.h"
#include <linux/kernel.h>
void do_other_func(void)
{
printk(KERN_INFO "other_func\n");
do_module_func();
}
Makefile
//Makefile
obj-m := mymodule.o
mymodule-objs := other_file.o
CROSS:=arm-unknown-linux-gnueabi-
KERNEL:= ~/work/linux-davinci-2.6.38/
ARCH:=arm
PWD:=$(shell pwd)
all:
$(MAKE) CROSS_COMPILE=$(CROSS) ARCH=$(ARCH) -C $(KERNEL) M=$(PWD) modules
clean:
$(MAKE) CROSS_COMPILE=$(CROSS) ARCH=$(ARCH) -C $(KERNEL) M=$(PWD) clean
I'm cross compiling but I believe this shouldn't be a problem.
make output:
make CROSS_COMPILE....
make[1]: Entering directory .../linux-davinci-2.6.38
CC [M] .../other_file.o
LD [M] .../mymodule.o
Building modules, stage 2.
MODPOST 1 modules
WARNING: "do_module_func" [.../mymodule.o] undefined! <--- warning here
CC .../mymodule.mod.o
LD [M] .../mymodule.ko
make[1]: Leaving directory .../linux-davinci-2.6.38
insmod output:
can't insert 'mymodule.ko': unknown symbol in module, or unknown parameter
dmesg:
mymodule: Unknown symbol do_mdule_func (err 0)
Thus the module compiles with a (linkage?) warning and the module doesn't load.
Now, I see that in the make output there appears to be a linkage attempt after compiling other_file.c, but shouldn't there be a compilation of also mymodule.c before the linkage?
Thanks! :)
Turns out the problem was in the Makefile. The 'trick' is that you define in obj-m the module that will be compiled (into a .ko) and in the -objs you write all the source files.
Thus the definitions in this Makefile turn to:
obj-m := moduleko.o
moduleko-objs := other_file.o mymodule.o
and this is compiled into moduleko.ko.
This is because file_2 required file_1 symbol reference for building file_2 as LKM.
To overcome this, build file_1(LKM) and place the Module.symvers of file_1 in file_2 location. And build the file_2 again.
all:
$(MAKE) CROSS_COMPILE=$(CROSS) ARCH=$(ARCH) -C $(KERNEL) M=$(PWD) modules
instead try like this
$(MAKE) -C $(KERNEL) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS) M=$(PWD) /
this will run each file and links with object.hope this would solve your problem

How to set standard c99 for compile android NDK project

I want to build small library which was written in C99 for Android, but compiler gave log as
note: use option -std=c99 or -std=gnu99 to compile your code
Where can I set it?
In your Android.mk add
LOCAL_CFLAGS += -std=c99
For example:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS += -std=c99
LOCAL_SRC_FILES := com_example_ndktest_TestLib.c
LOCAL_MODULE := com_example_ndktest_TestLib
include $(BUILD_SHARED_LIBRARY)
Make sure you add 'LOCAL_CFLAGS' after adding 'include $(CLEAR_VARS)'
An addendum to auselen's answer:
According to the NDK docs (kandroid.org mirror), LOCAL_CFLAGS will only apply to each module - if you want this behavior across an entire project, set APP_CFLAGS in Application.mk. Also, CFLAGS will cover C and C++ sources, CPPFLAGS covers C++ only.
As people may be arriving here looking to "set standard c99 for compile android NDK project", I think this needs an update.
For Android Studio 1.4 with Gradle 2.5, the c99 can be set in build.gradle
NOTE THAT THE CASE SENSITIVE SYNTAX WITHIN BUILD.GRADLE HAS CHANGED FROM cFlags TO CFlags (many examples online use the old syntax).
here is a build.gradle modified from the sample hello-jni project with C99 support added.
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.0"
defaultConfig.with {
applicationId = "com.example.hellojni"
minSdkVersion.apiLevel = 4
targetSdkVersion.apiLevel = 23
}
}
compileOptions.with {
sourceCompatibility=JavaVersion.VERSION_1_7
targetCompatibility=JavaVersion.VERSION_1_7
}
/*
* native build settings
*/
android.ndk {
moduleName = "hello-jni"
CFlags += "-std=c99"
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.txt')
}
}
android.productFlavors {
// for detailed abiFilter descriptions, refer to "Supported ABIs" #
// https://developer.android.com/ndk/guides/abis.html#sa
create("arm") {
ndk.abiFilters += "armeabi"
}
create("arm7") {
ndk.abiFilters += "armeabi-v7a"
}
create("arm8") {
ndk.abiFilters += "arm64-v8a"
}
create("x86") {
ndk.abiFilters += "x86"
}
create("x86-64") {
ndk.abiFilters += "x86_64"
}
create("mips") {
ndk.abiFilters += "mips"
}
create("mips-64") {
ndk.abiFilters += "mips64"
}
// To include all cpu architectures, leaves abiFilters empty
create("all")
}
}

Resources