【问题标题】:NDK - linking a shared libraryNDK - 链接共享库
【发布时间】:2018-01-24 07:39:30
【问题描述】:

我正在尝试将我编译的简单共享库 (libhello.so) 链接到我的本机 C++ 代码。 库 libhello.so 文件是:
1.get13.h

#ifndef GET13_H
#define GET13_H
int get13();
#endif

2。获取13.cpp

#include "get13.h"

int get13() {
    return 13;
}

Android 文件是:
1.MyApplication/jni/Android.mk

LOCAL_PATH := $(call my-dir)

LOCAL_MODULE := libhello
LOCAL_SRC_FILES := libhello.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := native-lib
LOCAL_SRC_FILES := native-lib.cpp
LOCAL_SHARED_LIBRARIES := libhello
include $(BUILD_SHARED_LIBRARY)

2。 MyApplication/jni/Application.mk

APP_STL := gnustl_static
APP_PLATFORM := android-24

3。 MyApplication/jni/libhello.so
4. MyApplication/jni/get13.h - 同上一个
5.MyApplication/jni/native-lib.cpp

#include <jni.h>
#include <string>
#include <sstream>
extern "C"{
#include <get13.h>
JNIEXPORT jint JNICALL
Java_com_example_semko_myapplication_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject asdf) {
    get13();
    return 1;
}
}

6。 MyApplication/app/build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    defaultConfig {
        applicationId "com.example.semko.myapplication"
        minSdkVersion 24
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    sourceSets.main {
        jni.srcDirs = []
        jniLibs.srcDir '../jni'
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        ndkBuild {
            path '../jni/Android.mk'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:24.2.1'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
}

7。 MyApplication/app/src/main/java/com.example.semko.myapplication/MainActivity.java

package com.example.semko.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(Integer.toString(stringFromJNI()));
    }

    public native int stringFromJNI();
}

问题是我在文件 native-lib.cpp 中的 gradle 构建期间收到此错误:

Error:(10) undefined reference to `get13'
Error:error: linker command failed with exit code 1 (use -v to see invocation)

我使用 Android NDK 包中包含的 make_standalone_toolchain.py 脚本生成的 android 工具链编译了 libhello。

【问题讨论】:

  • 您好,这是一个专门针对特定问题的网站,这里没有提出任何实际问题。一般性建议请求与主题无关。
  • 对不起,我已经更正了问题
  • 我对 ndk-build 不是很熟悉,因为我自己使用 cmake,但 MyApplication/jni/Android.mk 不应该在 .cpp.h 中包含所有 LOCAL_SRC_FILES 文件吗?跨度>
  • get13.cpp/h 中没有 extern "C",但在 native-lib.cpp 中,您将 get13.h 包含在 extern "C" 块中。您确定这不会导致链接器认为它应该寻找符号 get13 而不是 _Z5get13v (这将是它的错位 C++ 名称)?如果将#include &lt;get13.h&gt; 移动到extern "C" { 上方,是否也会出现同样的错误?
  • 您是否确保重新构建所有内容,以便它不会再次尝试链接现有的目标文件?您是否验证过该符号确实以预期的名称导出(例如使用arm-linux-androideabi-objdump.exe -T libhello.so)?

标签: android android-ndk


【解决方案1】:

只有 JNI 函数本身应该标记为extern "C",如下所示:

#include <jni.h>
#include <string>
#include <sstream>
#include <get13.h>

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_semko_myapplication_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject asdf) {
    get13();
    return 1;
}

如果你使用javah为你准备一个MyApplication/jni/native-lib.h,它会有

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_semko_myapplication_MainActivity_stringFromJNI(
    JNIEnv* env,
    jobject asdf);

为您,在 cpp 文件中,您将

#include "native-lib.h"

根本不需要extern "C"

为确保您的 Android.mk 对所有架构都有效,请考虑以下更改:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := libhello
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libhello.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := native-lib
LOCAL_SRC_FILES := native-lib.cpp
LOCAL_SHARED_LIBRARIES := libhello
include $(BUILD_SHARED_LIBRARY)

更新:重要的是include $(CLEAR_VARS)LOCAL_MODULE := libhello之前。

【讨论】:

  • 感谢您的回答,但我并没有真正调用 javah,因为 Android Studio 会处理这个问题。你想让我在 native-lib.cpp 中添加#include "native-lib.h" 吗?因为当我这样做时,我得到“致命错误:找不到'native-lib.h'文件”。并且让库文件依赖于 native-lib.h 不是一种选择。不幸的是,移动 extern "C" 并没有帮助。
  • 你不需要native-lib.h。我只想将其显示为一个选项。错误信息和以前一样吗? libhello.so 的导出符号是什么?
  • 错误信息是一样的。我不知道可以检查导出的符号。我会检查,我会回复你
  • 在 Mac 上,我使用 $NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-nm -D whatever.so
  • 一个棘手的问题可能是您需要为您为 libnative-lib.so构建的每个 ABI 预构建库 (libhello.so) >.
猜你喜欢
  • 2015-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-14
  • 1970-01-01
相关资源
最近更新 更多