如何使用Android的NDK使用mkfifo

时间:2014-11-23 16:03:14

标签: android android-ndk

最近我升级了NDK,现在我的应用程序崩溃,缺少符号mkfifo

E/dalvikvm(2031): dlopen("/data/app-lib/...mylib.so") failed: Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "mkfifo" referenced by "mylib.so"...

较旧的平台mkfifo是在sys/stat.h

中内联定义的
static __inline__ int mkfifo(const char *__p, mode_t __m) {
    return mknod(__p, (__m & ~S_IFMT) | S_IFIFO, (dev_t)0);
}

但是在平台版本21中,它被改为仅仅是外部的贬值:

extern int mkfifo(const char*, mode_t);

这样就解释了缺失的符号异常......我的问题是如何修复它?

2 个答案:

答案 0 :(得分:25)

如果您针对android-21平台标头构建,则会发生这种情况。将APP_PLATFORM中的jni/Application.mk设置为旧版本,使用旧标头进行构建,以确保只链接到之前可用的功能。

(在android-21之前,C库的功能和标题并没有真正发生重大变化,因此对于普通的C库函数,如果构建定位android-3并不重要或android-20。)

这已经被报道并且是故意行为,参见例如https://code.google.com/p/android/issues/detail?id=73725

如果您不需要使用android-21中的新功能,请使用较旧的标头进行构建。 (如果您想尝试为之前不存在的arm64-v8ax86_64进行构建,那么您定位旧平台版本并不重要; {{ 1}}将使用较旧的目标构建32位部分,使用支持它们的最旧目标构建64位部分。)

如果您想要尝试在ndk-build平台上有条件地使用新功能,如果在这样的平台上运行,您可能需要使用android-21dlopen来有条件地加载它,那么你需要复制新标题中的其他定义,以允许你使用旧的平台标题进行构建。

答案 1 :(得分:8)

我已经尝试了mstorsjo的修复,它似乎有效,但是我有点担心从他发布的链接看起来谷歌似乎并不认为这是一个好主意。结果我做了一些挖掘,似乎'正确'修复是运送多个APK,(至少)一个目标android-20及以下,另一个目标android-21及以上。

问题源于NDK的变化,以便在执行NDK构建时强制使用'fPIE'选项。来自NDK 10d release notes

  

从API级别21开始,在构建时使用-fPIE -pie。在API级别16及更高级别中,ndk-build在构建时使用PIE。此更改有许多含义,在开发人员预览版888中进行了讨论。这些含义不适用于共享库。

如果您查看Developer Preview Issue 888,则会说明以下内容:

  

Bionic commit 76e289c026f及其前身2aebf5429bb要求使用-fPIE -pie构建所有动态链接的本机可执行文件。这有许多可能无意的副作用,包括:

     
      
  • 在KitKat下正常运行的旧/未维护的应用程序现在可能无法在“L”下运行。这可能会影响即使不使用网络,处理不受信任的数据或定位新的“L”SDK API的简单应用程序。

  •   
  • 主动维护希望定位“L”的应用必须提供PIE可执行文件或静态可执行文件。 如果某个应用想要定位ICS或更低版本,则还必须提供非PIE可执行文件或静态可执行文件。即使是使用-fPIE -pie构建的简单“Hello world”程序也会在ICS和GB上进行分段。

  •   

显然,您可能更愿意使用之前的解决方案,但只是认为值得注意。