【问题标题】:Use C++ with Android ndk/jni将 C++ 与 Android ndk/jni 一起使用
【发布时间】:2011-09-19 08:48:26
【问题描述】:

所有 ndk 示例仅使用在标头中声明为 extern 并在 cpp 文件中定义的基本 C 函数。然后在包含jni回调的C文件中包含头文件后,一切正常。

是否可以在 android ndk 中使用 C++ 类?我的应用程序不会是原生活动,它仍然会有一个重要的 java 部分,但它会调用原生 C 代码进行 CPU 密集型计算(已经用 C++ 编写,带有类和其他 C++ 内容)。

这是我现在的 hello-world 结构:

文件“first.h”

#ifndef FIRST_H
#define FIRST_H

class Test
{};

#endif /* FIRST_H */

文件“second.cpp”

#include <jni.h>
#include "first.h"

#ifdef __cplusplus
extern "C" {
#endif

jint Java_com_example_twolibs_TwoLibs_add( JNIEnv*  env,
                                      jobject  this,
                                      jint     x,
                                      jint     y )
{
    Test t;
    return 0;
}

#ifdef __cplusplus
}
#endif

最后是 Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libtwolib-second
LOCAL_SRC_FILES := second.cpp

include $(BUILD_SHARED_LIBRARY)

相当基本,但无法编译。在 .c 文件中打开 second.cpp 在包含头文件时会引发错误,我猜这是因为它不是 C++ 文件。

error: expected '=', ',', ';', 'asm' or '__attribute__' before 'Test'

将其设为 .cpp 会引发以下错误:

make: *** No rule to make target `/cygdrive/c/android-ndk-r5c/samples/twolibs/jni/second.c', needed by `/cygdrive/c/android-ndk-r5c/samples/two-libs/obj/local/armeabi/objs/twolib-second/second.o'.  Stop.

知道如何编译那个东西吗?

谢谢

【问题讨论】:

    标签: c++ android c java-native-interface android-ndk


    【解决方案1】:

    编辑 Android.mk

    修改 LOCAL_SRC_FILES 的实例并从每行的开头删除 ./。

    【讨论】:

      【解决方案2】:

      运行:

      ndk-build clean
      

      在你修改了错误的Android.mk 之后,否则即使你已经修复了配置,构建也可能会继续失败。

      我认为这就是 OP 的意思 on this comment。

      【讨论】:

        【解决方案3】:

        关于您的编译错误,您似乎首先将其称为“second.c”,然后将其重命名为“second.cpp”,但目标文件中仍然包含“second.c”名称,因此在您编译之前(bdk -build) 你需要删除 /cygdrive/c/android-ndk-r5c/samples/two-libs/obj/local/armeabi/objs/twolib-second/ 目录下的 *.o 和 *.d 文件

        【讨论】:

          【解决方案4】:

          错误:在 'class' 之前应有 '='、','、';'、'asm' 或 '__ 属性 __'

          缺少';'的经典案例在 class 关键字之前?想象一下

           int functionname(int p)
           class X { } ;
          

          这可能很容易导致您的编译器消息。一个常见的复杂因素是它实际上看起来像什么时候

           #include "someheader.h"
           class X { } ;
          

          并且错误出现在 someheader.h / 或任何递归包含的文件 / 中的最后一个声明中;)

          【讨论】:

          • 我一开始也是这么想的,但我查了一下,这不是语法错误
          【解决方案5】:

          您可以将 C++ 与 NDK 一起使用,但带有 C++ 代码的文件必须具有 .cpp 扩展名。

          来自 ANDROID-MK.html:

          请注意,C++ 源文件的默认扩展名是“.cpp”。它是 但是可以通过定义变量来指定不同的 LOCAL_CPP_EXTENSION。不要忘记最初的点(即 '.cxx' 将 工作,但不是'cxx')。

          【讨论】:

          • 似乎回调 C 代码(包含要从 java 端调用的 Java_com_example_twolibs_TwoLibs_add 之类的调用的文件)必须位于 .c 文件(而不是 .cpp)中。否则它不会在我的机器上编译。因此,当我尝试包含一个包含类声明的头文件时,会出现同样的错误。
          • 把所有东西都变成 .cpp 文件给了我一个 make: *** No rule to make target error 这意味着 make 文件找不到源文件......但如果我把它们变成.c 文件,所以我猜这不是路径问题
          • 必须编译,但需要在所有JNI函数中添加external "C"。您是否更改了 makefile 中的源文件扩展名?
          • 是的,我尝试在 jni 函数周围添加 extern "C"(我还在帖子中更新了我的代码)但仍然出现相同的错误“make: *** No rule to make target...” . make文件中的文件扩展名也是正确的
          • 好的,您的解决方案实际上是正确的,但我忘记清理一些 .o 文件,因此 make 仍在寻找 .c 文件。一旦我清理了所有东西并运行了新的 ndk-build,一切正常。谢谢!
          【解决方案6】:

          您必须重新编译所有专门针对 Android 的本机库。您确实需要您计划使用的所有第 3 方本机库的源代码,因为通常当我们在 Android 外部编译和链接这些库时,它们会链接到 glibc,但不幸的是,由于许可和性能,Android 不使用 glibc问题。 Android 使用了一个淡化版本的glibc,称为libc。对于大多数常用功能,它具有与 glibc 匹配的符号名称。但据我所知,libc 没有一些与strings 相关的功能,而且它肯定没有一些posix 支持。如果您的本机库正在使用任何已弃用的功能,您将必须通过使用libc 支持的替代功能并相应地对您的库进行编码来找到解决方法。

          此外,正如您正确指出的那样,您将不得不使用 NDK 将 Java(Android 应用程序/fwk)连接到原生世界(C++)。

          虽然这听起来很简单,但根据我在 Android 上编译原生库(Android 移植)的经验,传统上这非常耗时,而且无法保证成功。

          【讨论】:

          • 感谢您的回答。实际上,我什至无法开始移植我的 3rd 方库,因为一旦我在其中使用类,我什至无法获得一个简单的类似 hello-world 的测试来编译。第一步是创建一个几乎空的本机 C++ 测试类并在我的 jni 回调 C 文件中使用它。只是看看它是否编译。
          猜你喜欢
          • 1970-01-01
          • 2012-03-16
          • 2016-07-13
          • 2012-03-25
          • 1970-01-01
          • 1970-01-01
          • 2017-08-11
          • 2013-08-05
          • 1970-01-01
          相关资源
          最近更新 更多