安卓链接器 : undefined reference to bsd_signal

标签 android android-ndk static-libraries build.gradle

我正在运行 gradlew 来编译一个具有静态库依赖项的 Android 应用程序。不知何故,我对 bsd_signal 有一个 undefined reference 。

我能够使用 gradle 1.X 编译这个应用程序,但我不得不切换到 gradle 2.10 并删除我的 Android.mk 文件以支持将更多构建指令放入我的 gradle.build 文件,这就是问题所在。

谁能告诉我是否有定义 bsd_signal 的库,我应该将其链接到我的项目?

编译器输出

Starting process 'command '/home/myself/Android/Sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++''. Working directory: /home/myself/projects/DroidEar/app Command: /home/myself/Android/Sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++ @/home/myself/projects/DroidEar/app/build/tmp/linkNativeArmeabi-v7aDebugSharedLibrary/options.txt
Successfully started process 'command '/home/myself/Android/Sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++''
/android/ndk/platforms/android-9/arch-arm/usr/include/signal.h:113: error: undefined reference to 'bsd_signal'
/android/ndk/platforms/android-9/arch-arm/usr/include/signal.h:113: error: undefined reference to 'bsd_signal'
collect2: error: ld returned 1 exit status

TMI:这是我的 gradle.build 文件

apply plugin: 'com.android.model.application'

model {
    repositories {
        libs(PrebuiltLibraries) {            
            Superpowered {
                binaries.withType(StaticLibraryBinary) {
                    def prefix = "src/main/jniLibs/Superpowered"
                    headers.srcDir "${prefix}"
                    if (targetPlatform.getName() == "armeabi-v7a")
                        staticLibraryFile = file("${prefix}/libSuperpoweredAndroidARM.a")
                    else if (targetPlatform.getName() == "arm64-v8a")
                        staticLibraryFile = file("${prefix}/libSuperpoweredAndroidARM64.a")
                    else if (targetPlatform.getName() == "x86_64")
                        staticLibraryFile = file("${prefix}/libSuperpoweredAndroidX86_64.a")
                    else if (targetPlatform.getName() == "X86")
                        staticLibraryFile = file("${prefix}/libSuperpoweredAndroidX86.a")
                }
            }
        }
    }

    android {
        compileSdkVersion = 23
        buildToolsVersion = "23.0.3"

        sources {
            main {
                jni {
                    dependencies {
                        library "Superpowered" linkage "static"
                    }
                }
            }
        }

        ndk {
            ldLibs.addAll(['log', 'android', 'c'])
        }

        defaultConfig {
            applicationId = "edu.ucdavis.auditoryenhancer"
            minSdkVersion.apiLevel = 22
            targetSdkVersion.apiLevel = 23
            versionCode = 1
            versionName = "1.0"
        }
    }

    android.ndk {
        moduleName = "native"
    }

    android.buildTypes {
        release {
                minifyEnabled = false
                proguardFiles.add(file("proguard-rules.pro"))
        }
    }
}


dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
}

在我看来,bsd_signal 是在 platforms/android-9/arch-x86/usr/lib/libc 的 signal.o 组件中定义的.a,但即使我的 ldLibs 调用上面包含 c,我也会收到错误。

最佳答案

直到 android-19 包含 NDK-s signal.h 声明 bsd_signal externsignal 是一个内联调用bsd_signal

android-21 开头的 signal 是一个 externbsd_signal 根本没有声明。

有趣的是,bsd_signalNDK r10e android-21 libc.so 中仍可用作符号(因此没有链接错误如果使用 r10e),但在 NDK r11 及更高版本中不可用。

从 NDK-s android-21+ libc.so 中删除 bsd_signal 如果使用 android 构建的代码会导致链接错误-21+ 与调用 signalbsd_signal 的较低 NDK 级别构建的静态库链接。调用 signal 的最流行的库是 OpenSSL

警告:使用 android-21+ 构建那些静态库(这会直接放置 signal 符号)会很好地链接,但会导致在 *.so 中,由于在他们的 libc.so 中找不到 signal 符号,无法在较旧的 Android 操作系统设备上加载。

因此,对于任何调用 signalbsd_signal 的代码,最好坚持使用 <=android-19

为了链接一个用 构建的库,我最终声明了一个 bsd_signal 包装器,它将从 libc 调用 bsd_signal .so(它在设备的 libc.so 中仍然可用,甚至到 Android 7.0)。

#if (__ANDROID_API__ > 19)
#include <android/api-level.h>
#include <android/log.h>
#include <signal.h>
#include <dlfcn.h>

extern "C" {
  typedef __sighandler_t (*bsd_signal_func_t)(int, __sighandler_t);
  bsd_signal_func_t bsd_signal_func = NULL;

  __sighandler_t bsd_signal(int s, __sighandler_t f) {
    if (bsd_signal_func == NULL) {
      // For now (up to Android 7.0) this is always available 
      bsd_signal_func = (bsd_signal_func_t) dlsym(RTLD_DEFAULT, "bsd_signal");

      if (bsd_signal_func == NULL) {
        // You may try dlsym(RTLD_DEFAULT, "signal") or dlsym(RTLD_NEXT, "signal") here
        // Make sure you add a comment here in StackOverflow
        // if you find a device that doesn't have "bsd_signal" in its libc.so!!!

        __android_log_assert("", "bsd_signal_wrapper", "bsd_signal symbol not found!");
      }
    }

    return bsd_signal_func(s, f);
  }
}
#endif

附言。看起来 bsd_signal 符号将被带回 NDK r13 中的 libc.so:

https://github.com/android-ndk/ndk/issues/160#issuecomment-236295994

关于安卓链接器 : undefined reference to bsd_signal,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36746904/

相关文章:

java - 如何执行具有异步子任务的顺序任务

安卓:意向服务。在哪里保存文件?

android应用内计费安全验证方法总是返回false

Android Studio Cmake 构建错误 : invalid conversion between vector type

android - 如何将 OpenSSL 指向 Android 设备上的根证书?

c++ - 如何 C++ 静态编译第三方库,其中包含其他人在主应用程序中使用的另一个库

c++ - 我可以在 DLL 中创建第二个单例实例吗?

android - Android View 标记何时需要结束标记?

ios - 如何在 iOS 中包含两个几乎相同的静态库

android - Android OpenCV手势识别