首页 > 解决方案 > “未定义的引用错误”故障排除 - Android Studio/CMake/Clang++A

问题描述

我正在尝试设置HelloJNI 教程来编译本机库并将其链接到示例创建的默认库。

文件结构如下:

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

文件夹中的CMakeLists.txtlibs文件看起来很像这样:

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)

对于每个库。cuse依赖fuse,并且fuse依赖bthread,并且每个库都设置为 SHARED 中add_library()。这一切都编译和链接没有错误。

整个app/CMakeLists.txt项目的情况是:

# 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})

在构建项目时,我总是收到一个未定义的引用错误,它指的是cuse.c. 例如:

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*)'

我已经修改app/CMakeLists.txt' several times to try and link to the了 cuse 库。

头文件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

据我所知,cuse库编译得很好。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

multiple definition我相信我可以通过回滚到以前的版本来修复错误,但是我不知道接下来要尝试什么未定义的参考错误。

我的问题是:下一步如何修复/解决此错误:似乎 CMake 没有正确链接库,但我对 CMake 或链接器不够熟悉,不知道如何调试它。我已经尝试了很多不同的 CMake 命令来链接库和导出符号,但它们似乎都没有在任何组合中工作。

如何cmake从 bash 运行、查看cmake和/或ld的详细输出并找到错误?

更新

我没有意识到find_library()仍然app/CMakeLists.txt被注释掉了。取消注释该行会产生以下错误:

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

标签: androidc++android-studiocmakeclang

解决方案


推荐阅读