我正在尝试设置HelloJNI tutorial来编译本机库并将其链接到该示例创建的默认库。
文件结构如下:
├── app
│ ├── libs
│ │ ├── bthread
│ │ │ ├── CMakeLists.txt
│ │ │ └── include
│ │ ├── cuse
│ │ │ ├── CMakeLists.txt
│ │ │ └── include
│ │ └── fuse
│ │ ├── CMakeLists.txt
│ │ ├── include
│ │ └── modules
│ └── src
│ ├── main
│ │ ├── cpp
│ │ │ ├── hello-jni.cpp
│ │ │ └── daemon.cpp
CMakeLists.txt
文件夹中的库的libs
文件看起来非常像这样:
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
,并且每个库在add_library()
中都设置为SHARED。所有这些都可以正确编译和链接。
整个项目的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命令来链接库和导出符号,但它们似乎都无法以任何组合使用。
我如何从bash运行cmake
,查看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