Android链接器:对bsd_信号的未定义引用

Android链接器:对bsd_信号的未定义引用,android,android-ndk,static-libraries,build.gradle,Android,Android Ndk,Static Libraries,Build.gradle,我正在运行gradlew来编译一个具有静态lib依赖项的Android应用程序。不知何故,我对bsd\U信号有一个未定义的引用 我能够用gradle 1.X编译这个应用程序,但我不得不切换到gradle 2.10,并放弃我的Android.mk文件,转而在我的gradle.build文件中加入更多的构建指令,这就是问题所在 有谁能告诉我是否有一个定义bsd\U信号的库,我应该链接到我的项目 编译器输出 Starting process 'command '/home/myself/Android

我正在运行
gradlew
来编译一个具有静态lib依赖项的Android应用程序。不知何故,我对bsd\U信号有一个未定义的引用

我能够用gradle 1.X编译这个应用程序,但我不得不切换到gradle 2.10,并放弃我的
Android.mk
文件,转而在我的
gradle.build
文件中加入更多的构建指令,这就是问题所在

有谁能告诉我是否有一个定义bsd\U信号的库,我应该链接到我的项目

编译器输出

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\u信号
是在
platforms/android-9/arch-x86/usr/lib/libc.a的
signal.o
组件中定义的,但即使我上面的
ldLibs
调用包括
c
,我也会得到错误。

这是android NDK中的ABI破坏。使用signal()使用android-21之前的NDK构建的库/二进制文件无法与android-21或更高版本一起使用。反过来说。这张铁锈票有更详细的解释:


还有这张安卓NDK的票:

直到Android-19包括NDK-s
signal.h
声明了
bsd\U信号
extern和
signal
是一个内联呼叫
bsd\U信号

以android-21
signal
开头是一个extern,
bsd\u signal
根本没有声明

有趣的是,
bsd_信号
NDK r10e android-21
libc中仍然可以作为符号使用。因此
(因此使用r10e时没有链接错误),但在NDK r11及以上版本中不可用

从NDK-sandroid-21+
libc中删除
bsd\u信号
。因此,如果使用android-21+构建的代码与调用
信号或
bsd\u信号的较低NDK级别构建的静态libs链接,则
会导致链接错误。最流行的调用
信号的库是OpenSSL

警告:使用android-21+构建那些静态LIB(将直接放置
信号
符号)将链接正常,但会导致
*。因此
无法加载到较旧的android操作系统设备上,因为
信号
符号未在它们的
libc中找到。因此


因此,最好还是坚持使用,而且可能需要使用此标题#ifdef uuuuuuuu安卓uuu#include#include#include##endif@AntonPechenko是的,当然,让我们把它们放在我答案的代码中。如果找不到bsd_信号,那么尝试通过dlsym加载信号是否有意义,因为其中一个信号总是可用的?据我所知,在Android 7.0之前,bsd_信号已经在设备的libc.so中被发现,并且bsd_信号将在r13中恢复,但由于Android设备种类繁多,这似乎是一种合理的保护措施。会有任何负面后果吗?我不认为会有任何负面后果,我以前在代码注释中把它作为一个建议,tbh我在我的生产代码中有它以防将来。我唯一不喜欢的是,我在代码上测试了“信号”在Android 6.0和7.0设备上,使用RTLD_默认值获取的地址与从dlopen(“libc.so”)返回的句柄获取的地址不同。RTLD_接下来也有同样的问题。因此,在我的生产代码中,我从RTLD_NEXT获取“信号”。当然,我可以使用dlopen来确保获得正确的“信号”符号,但我希望我的代码尽可能干净,而无需在关闭应用程序时在某处调用dlclose以减少引用计数器。不过,我不是POSIX/Linux专家,而且我非常确信,在没有dlclose的情况下,杀死该应用程序不会造成任何泄漏。总而言之:这只是我的学究气;)
#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