0

I am trying to setup the HelloJNI tutorial to compile and link a native library to the default library the example creates.

The file structure is as follows:

├── app
│   ├── libs
│   │   ├── bthread
│   │   │   ├── CMakeLists.txt
│   │   │   └── include
│   │   ├── cuse
│   │   │   ├── CMakeLists.txt
│   │   │   └── include
│   │   └── fuse
│   │       ├── CMakeLists.txt
│   │       ├── include
│   │       └── modules
│   └── src
│       ├── main
│       │   ├── cpp
│       │   │   ├── hello-jni.cpp
│       │   │   └── daemon.cpp

The CMakeLists.txt file for the libraries in the libs folder looks pretty much like this:

cmake_minimum_required(VERSION 3.4.1)

# Create a library called "Hello" which includes the source file "hello.cxx".
# The extension is already found. Any number of sources could be listed here.

include_directories(
    ${CMAKE_SOURCE_DIR}/lib/fuse/include
    ${CMAKE_SOURCE_DIR}/lib/cuse/include)


add_library    (cuse    SHARED
                        cuse.c)

add_executable (cuse_client cuse_client.c)


# Make sure the compiler can find include files for our Hello library
# when other libraries or executables link to Hello

target_include_directories(cuse PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>)

set_target_properties(cuse PROPERTIES PUBLIC_HEADER  "include/cuse.h")

target_link_libraries( # Specifies the target library.
                       cuse
                       fuse)

install(TARGETS cuse
    EXPORT cuse-targets
    PUBLIC_HEADER DESTINATION include
    ARCHIVE DESTINATION lib
    LIBRARY DESTINATION lib
    RUNTIME DESTINATION bin)

install(EXPORT cuse-targets
    NAMESPACE cuse::
    FILE cuse-config.cmake
    DESTINATION lib/cmake/cuse)

For each library. cuse depends on fuse, and fuse depends on bthread, and each library is set to SHARED in add_library(). This all compiles and links with no errors.

The app/CMakeLists.txt for the whole project is:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

project(app)

include_directories(
    ${CMAKE_SOURCE_DIR}/libs/cuse/include
    ${CMAKE_SOURCE_DIR}/libs/fuse/include)


add_subdirectory(libs/bthread)
add_subdirectory(libs/fuse)
add_subdirectory(libs/cuse)

#find_library(LIB_CUSE NAMES cuse libcuse HINTS libs libs/cuse)

add_library(hello-jni SHARED    src/main/cpp/hello-jni.cpp
                                src/main/cpp/daemon.cpp)



target_link_libraries( # Specifies the target library.
                       hello-jni
                       ${LIB_CUSE})

When building the project, I always receive an Undefined reference error referring to one or more functions in cuse.c. For example:

src/main/cpp/daemon.cpp.o: In function `start_cuse_server()':
src/main/cpp/daemon.cpp:65: undefined reference to `cusexmp_process_arg(void*, char const*, int, fuse_args*)'

I've modified app/CMakeLists.txt' several times to try and link to thecuse` library.

The header file cuse.h:

#ifndef CUSE_H
#define CUSE_H

#include "cuse_lowlevel.h"
#include <fuse_opt.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include "ioctl.h"

#define CUSEXMP_OPT(t, p) { t, offsetof(struct cusexmp_param, p), 1 }

void *cusexmp_buf;
size_t cusexmp_size;

int cusexmp_resize(size_t new_size);

void cusexmp_open(fuse_req_t req, struct fuse_file_info *fi);

void cusexmp_read(fuse_req_t req, size_t size, off_t off,
                         struct fuse_file_info *fi);

int cusexmp_expand(size_t new_size);

void cusexmp_write(fuse_req_t req, const char *buf, size_t size,
                          off_t off, struct fuse_file_info *fi);

void fioc_do_rw(fuse_req_t req, void *addr, const void *in_buf,
                       size_t in_bufsz, size_t out_bufsz, int is_read);

void cusexmp_ioctl(fuse_req_t req, int cmd, void *arg,
                          struct fuse_file_info *fi, unsigned flags,
                          const void *in_buf, size_t in_bufsz, size_t out_bufsz);

int cusexmp_process_arg(void *data, const char *arg, int key,
                               struct fuse_args *outargs);

struct cusexmp_param {
    unsigned        major;
    unsigned        minor;
    char            *dev_name;
    int         is_help;
};

const struct cuse_lowlevel_ops cusexmp_clop = {
        .open       = cusexmp_open,
        .read       = cusexmp_read,
        .write      = cusexmp_write,
        .ioctl      = cusexmp_ioctl,
};

const struct fuse_opt cusexmp_opts[] = {
        CUSEXMP_OPT("--maj=%u",     major),
        CUSEXMP_OPT("-m %u",        minor),
        CUSEXMP_OPT("--min=%u",     minor),
        CUSEXMP_OPT("-n %s",        dev_name),
        CUSEXMP_OPT("--name=%s",    dev_name),
        FUSE_OPT_KEY("-h",      0),
        FUSE_OPT_KEY("--help",      0),
        FUSE_OPT_END
};

const char *usage =
        "usage: cusexmp [options]\n"
                "\n"
                "options:\n"
                "    --help|-h             print this help message\n"
                "    --maj=MAJ|-M MAJ      device major number\n"
                "    --min=MIN|-m MIN      device minor number\n"
                "    --name=NAME|-n NAME   device name (mandatory)\n"
                "    -d   -o debug         enable debug output (implies -f)\n"
                "    -f                    foreground operation\n"
                "    -s                    disable multi-threaded operation\n"
                "\n";


#endif

As far as I can tell the cuse library compiles fine. Sample output from Gradle:

Build hello-jni arm64-v8a
[1/3] Building CXX object CMakeFiles/hello-jni.dir/src/main/cpp/hello-jni.cpp.o
[2/3] Building CXX object CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o
/home/mike/Desktop/hellojni/app/src/main/cpp/daemon.cpp:76:20: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]
    param.dev_name="/dev/chardev_test";
                   ^
1 warning generated.
[3/3] Linking CXX shared library ../../../../build/intermediates/cmake/debug/obj/arm64-v8a/libhello-jni.so
FAILED: : && /data/android-ndk-r17b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++  --target=aarch64-none-linux-android --gcc-toolchain=/data/android-ndk-r17b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64 --sysroot=/data/android-ndk-r17b/sysroot -fPIC -isystem /data/android-ndk-r17b/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11  -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot /data/android-ndk-r17b/platforms/android-21/arch-arm64 -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -L/data/android-ndk-r17b/sources/cxx-stl/llvm-libc++/libs/arm64-v8a -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libhello-jni.so -o ../../../../build/intermediates/cmake/debug/obj/arm64-v8a/libhello-jni.so CMakeFiles/hello-jni.dir/src/main/cpp/hello-jni.cpp.o CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o  -latomic -lm "/data/android-ndk-r17b/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_static.a" "/data/android-ndk-r17b/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++abi.a" && :
CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o:(.bss+0x0): multiple definition of `cusexmp_buf'
CMakeFiles/hello-jni.dir/src/main/cpp/hello-jni.cpp.o:(.bss+0x0): first defined here
CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o: In function `__daemon_init()':
/home/mike/Desktop/hellojni/app/src/main/cpp/daemon.cpp:65: multiple definition of `cusexmp_size'
CMakeFiles/hello-jni.dir/src/main/cpp/hello-jni.cpp.o:/data/android-ndk-r17b/sources/cxx-stl/llvm-libc++/include/string:1543: first defined here
CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o: In function `__daemon_init()':
/home/mike/Desktop/hellojni/app/src/main/cpp/daemon.cpp:65: multiple definition of `usage'
CMakeFiles/hello-jni.dir/src/main/cpp
/hello-jni.cpp.o:/data/android-ndk-r17b/sources/cxx-stl/llvm-libc++/include/string:1543: first defined here
CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o: In function `start_cuse_server()':
/home/mike/Desktop/hellojni/app/src/main/cpp/daemon.cpp:65: undefined reference to `cusexmp_process_arg(void*, char const*, int, fuse_args*)'
/home/mike/Desktop/hellojni/app/src/main/cpp/daemon.cpp:65: undefined reference to `cusexmp_process_arg(void*, char const*, int, fuse_args*)'
/home/mike/Desktop/hellojni/app/src/main/cpp/daemon.cpp:81: undefined reference to `fuse_opt_parse'
/home/mike/Desktop/hellojni/app/src/main/cpp/daemon.cpp:101: undefined reference to `cuse_lowlevel_main'
CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o:(.data.rel.ro+0xd8): undefined reference to `cusexmp_open(fuse_req*, fuse_file_info*)'
CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o:(.data.rel.ro+0xe0): undefined reference to `cusexmp_read(fuse_req*, unsigned long, long, fuse_file_info*)'
CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o:(.data.rel.ro+0xe8): undefined reference to `cusexmp_write(fuse_req*, char const*, unsigned long, long, fuse_file_info*)'
CMakeFiles/hello-jni.dir/src/main/cpp/daemon.cpp.o:(.data.rel.ro+0x108): undefined reference to `cusexmp_ioctl(fuse_req*, int, void*, fuse_file_info*, unsigned int, void const*, unsigned long, unsigned long)'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
:app:externalNativeBuildDebug FAILED

The multiple definition errors I beleive I can fix by rolling back to a previous version, but the undefined reference errors I don't know what to try next.

My Question is: How to next fix/troubleshoot this error: It appears that CMake is not linking the library properly, but I'm not familiar enough with CMake or linkers to know how to debug this. I've tried a lot of different CMake commands for linking libraries and exporting symbols, none of them have seemed to work in any combination.

How do I run cmake from bash, view verbose output from cmake and/or ld and find the error?

Update

I didn't realize find_library() in app/CMakeLists.txt was still commented out. Uncommenting that line yields the following error:

CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
LIB_CUSE
    linked by target "hello-jni" in directory /home/mike/Desktop/hellojni/app
MDMoore313
  • 3,233
  • 1
  • 23
  • 38
  • Is the variable ${LIB_CUSE} well-defined? It seems that the `target_link_libraries` is the issue here. As the line `find_library(LIB_CUSE NAMES cuse libcuse HINTS libs libs/cuse)` is commented that may be the problem. – Benjamin Barrois Jul 25 '18 at 14:54
  • @BenjaminBarrois I didn't realize it was still commented out. A leftover from yesterday's troubleshooting session. I've updated the question. I've also set it to the libname, same result. – MDMoore313 Jul 25 '18 at 15:08
  • Have you tried `target_link_libraries(hello-jni cuse fuse bthread)` ? – Benjamin Barrois Jul 25 '18 at 15:12
  • Yep, but I tried it again just now for sanity: Same error, undefined reference. – MDMoore313 Jul 25 '18 at 15:15
  • Looks like the library simply doesn't **define** these symbols for outer use. (The header `cuse.h` only *declares* them.) I have able only to google code which defines those symbols *statically*: https://libfuse.github.io/doxygen/cuse_8c_source.html. BTW, you want to use these functions (e.g. `cusexmp_process_arg`), but how do you now what they do? Have you found documentation for them, or what? – Tsyvarev Jul 25 '18 at 23:17
  • @Tsyvarev I've tried using the extern keyword, no change. How do I define the functions for outer use?? – MDMoore313 Jul 25 '18 at 23:19
  • 1
    "How do I define the functions for outer use??" - Define that functions in `cuse.c` without `static` modifier. – Tsyvarev Jul 25 '18 at 23:21
  • Possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Tsyvarev Jul 26 '18 at 00:06

0 Answers0