# JNI wrapper complaining about undefined references

I'm trying to use the TagLib library in an Android app. As far as I know, I have to write a JNI wrapper for it. I wanted to try something simple - read the title from the tag.

I wrote the following code in Java:

package developer.rogan.taglib;

import android.support.annotation.NonNull;
import android.util.Log;

public class TagJNI {

private static final String TAG = "TagJNI";

private String filename;
private String title;

public TagJNI(@NonNull String filename) {
this.filename = filename;
}

public String getTitle() {
Log.d(TAG, "getTitle, filename = " + filename);
this.title = taglibGetTitle(filename);
return title;
}

private native String taglibGetTitle(String filename);
}

Android Studio then gave me the option to automatically generate the function in native code (the file is called tagjni.c). I added some of my own code to add functionality:

#include <jni.h>
#include "../../../../../../Development/C++/taglib-1.11.1/bindings/c/tag_c.h"

TagLib_File *file;
TagLib_Tag *tag;
char *title;

JNIEXPORT jstring JNICALL
Java_developer_rogan_taglib_TagJNI_taglibGetTitle(JNIEnv *env, jobject instance,
jstring filename_) {

taglib_set_strings_unicode(JNI_FALSE);
const char *filename = (*env)->GetStringUTFChars(env, filename_, 0);

file = taglib_file_new(filename);
tag = taglib_file_tag(file);
title = taglib_tag_title(tag);
taglib_file_free(file);
(*env)->ReleaseStringUTFChars(env, filename_, filename);
return (*env)->NewStringUTF(env, title);
}

There's something going on with the include statement too. I can write #include and then the other include says that it's unused. However, when I delete it, none of the variables are recognised anymore. When I hover over the errors, I get the option to add the #include.

When I try to run the app, I get the following error (and some more similar ones): undefined reference to 'taglib_set_strings_unicode'

Does this mean that the function I'm calling cannot be found? I had a lot of issues setting the library up and finally got it to work somehow. As I started writing the JNI wrapper, Android Studio complained about the .c file not being included in the project. After looking at the NDK web page I figured I have to create one root CMakeLists.txt and reference the other two (one for TagLib and one for JNI wrapper). I know very little about C and CMakeLists. This is what I came up with:

cmake_minimum_required(VERSION 3.4.1)

add_subdirectory( # Specifies the directory of the CMakeLists.txt file.
# Specifies the directory for the build outputs.

add_subdirectory( # Specifies the directory of the CMakeLists.txt file.
# Specifies the directory for the build outputs.
/home/adrijan/devel/tagtest/taglib )

TagLib already includes a CMakeLists so I just pointed to it. For the JNI wrapper, I placed CMakeLists.txt inside the directory where the code is:

cmake_minimum_required(VERSION 3.4.1)

# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.

add_library( # Specifies the name of the library.
jni-taglib

# Sets the library as a shared library.
SHARED

# Provides a relative path to your source file(s).
tagjni.c )

# Specifies a path to native header files.
include_directories(tagjni.h)

It seems to me that I'm missing something really obvious here. I believe it has to do something with the way I set up CMake, but I can't figure it out.