【问题标题】:Compile native C++ shared object with Android NDK使用 Android NDK 编译原生 C++ 共享对象
【发布时间】:2015-01-05 08:22:46
【问题描述】:

我在 Linus 上通过 C++ 生成了一个.so 文件,现在生成了.so 文件我已经为Android ARM 交叉编译了这个.so 文件,所以我必须通过Android NDK 编译它,以便新生成.so 可以在我的android项目中使用。

所以任何人都可以帮助我将 Linux 生成的 .so 文件放在我的 Android 项目中,以及在 Make 文件(Android.mk)中添加什么,以便它可以使用我之前的现有方法生成新的 .so 文件Linux 生成.so 文件。

希望大家都清楚我的问题,如果没有请告诉我。

请帮助我。提前致谢

【问题讨论】:

  • 您在使用 Eclipse 吗?如果是这样,您是否启用了本机项目支持(已经有一段时间了,但我认为这就是它的名称)?不过,如果是 Eclipse,您将需要同时使用 Application.mk 和 Android.mk。
  • 是的,我正在使用 Eclipse,我从 stackoverflow.com/questions/9870435/… 获得了帮助,但我得到 .so 文件格式无法识别,我的 android 项目中有 Android.mk 文件,并且我启用了 NDK 支持
  • 您不会交叉编译 .so 文件。你交叉编译它的源代码。
  • 但我不知道如何交叉编译源代码。是否无法交叉编译.so文件
  • .so 文件包含您编译它的系统的机器代码。你需要交叉编译它,就像你想创建一个本地可执行文件一样。如果您不知道/不了解如何执行此操作,则需要查看如何为 Android 进行交叉编译。

标签: android c++ android-ndk


【解决方案1】:

以下是构建本机 C++ 共享对象的步骤。

  1. 为您的项目添加本机支持。请参阅 Android 的 Add native support
  2. 将 C++ 文件添加到 JNI 文件夹中
  3. 创建一个Android.mk,将其添加到 JNI 文件夹,然后添加您想要支持的架构。例如:

    APP_ABI   := armeabi x86 mips armeabi-v7a
    
  1. 选择一个 C++ 运行时库。请参阅 NDK 中的 CPLUSPLUS.README。我为运行时选择了 STL 端口(GNU 运行时由于其许可证而有毒)。

  2. 创建一个Appication.mk,将其添加到JNI 文件夹中,然后添加魔法。例如:

    LOCAL_PATH := $(call my-dir)
    
    # NDK_DEBUG_IMPORTS := 1
    
    #########################################################
    # STLport library
    include $(CLEAR_VARS)
    
    STLPORT_INCL     := /opt/android-ndk-r9/sources/cxx-stl/stlport/stlport
    STLPORT_LIB      := /opt/android-ndk-r9/sources/cxx-stl/stlport/libs/$(TARGET_ARCH_ABI)
    
    LOCAL_MODULE := stlport_shared
    LOCAL_SRC_FILES := $(STLPORT_LIB)/libstlport_shared.so
    
    LOCAL_EXPORT_CPPFLAGS :=
    LOCAL_EXPORT_C_INCLUDES := $(STLPORT_INCL)
    
    include $(PREBUILT_SHARED_LIBRARY)
    
    LOCAL_SHARED_LIBRARIES  := stlport_shared
    
    #########################################################
    # Crypto++ library
    include $(CLEAR_VARS)
    
    CRYPTOPP_INCL   := /usr/local/cryptopp/android-$(TARGET_ARCH_ABI)/include
    CRYPTOPP_LIB    := /usr/local/cryptopp/android-$(TARGET_ARCH_ABI)/lib
    
    LOCAL_MODULE       := cryptopp
    LOCAL_SRC_FILES    := $(CRYPTOPP_LIB)/libcryptopp.so
    
    LOCAL_EXPORT_CPPFLAGS := -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function
    LOCAL_EXPORT_C_INCLUDES := $(CRYPTOPP_INCL) $(CRYPTOPP_INCL)/cryptopp
    
    include $(PREBUILT_SHARED_LIBRARY)
    
    LOCAL_SHARED_LIBRARIES  := cryptopp
    
    #########################################################
    # PRNG library
    include $(CLEAR_VARS)
    
    APP_STL         := stlport_shared
    APP_MODULES     := prng stlport_shared cryptopp
    
    # My ass... LOCAL_EXPORT_C_INCLUDES is useless
    LOCAL_C_INCLUDES   := $(STLPORT_INCL) $(CRYPTOPP_INCL)
    
    LOCAL_CPP_FEATURES := rtti exceptions
    
    LOCAL_CPP_FLAGS    := -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function
    LOCAL_CPP_FLAGS    += -Wl,--exclude-libs,ALL
    
    LOCAL_LDLIBS            := -llog -landroid
    LOCAL_SHARED_LIBRARIES  := cryptopp stlport_shared
    
    LOCAL_MODULE    := prng
    LOCAL_SRC_FILES := libprng.cpp
    
    include $(BUILD_SHARED_LIBRARY)
    

我的库依赖于 STLport。 "STLport library" 后面的内容确保我的库是针对 stlport_shared.so 编译的,并且 stlport_shared.so 被复制到 APK 中。

我的库也依赖于cross-compiled version of Crypto++。 Crypto++ 也被编译/链接到stlport_shared.so。 "Crypto++ library" 后面的内容确保我的库是针对 libcryptopp.so 编译的,并且 libcryptopp.so 被复制到 APK 中。

最后,我的图书馆被调出。我的库是 "PRNG library" 之后的东西(它是一个文件测试项目)。它构建 libprng.so,并确保将 libprng.so 复制到 APK 中。

您还需要 Android 课程。这是我的样子。

package com.cryptopp.prng;

public class PRNG {

    static {
        System.loadLibrary("stlport_shared");
        System.loadLibrary("cryptopp");
        System.loadLibrary("prng");
    }

    private static native int CryptoPP_Reseed(byte[] bytes);

    private static native int CryptoPP_GetBytes(byte[] bytes);

    private static Object lock = new Object();

    // Class method. Returns the number of bytes consumed from the seed.
    public static int Reseed(byte[] seed) {         
        synchronized (lock) {
            return CryptoPP_Reseed(seed);
        }
    }

    // Class method. Returns the number of bytes generated.
    public static int GetBytes(byte[] bytes) {
        synchronized (lock) {
            return CryptoPP_GetBytes(bytes);
        }
    }

    // Instance method. Returns the number of bytes consumed from the seed.
    public int reseed(byte[] seed) {
        synchronized (lock) {
            return CryptoPP_Reseed(seed);
        }
    }

    // Instance method. Returns the number of bytes generated.
    public int getBytes(byte[] bytes) {
        synchronized (lock) {
            return CryptoPP_GetBytes(bytes);
        }
    }
}

Android 修改后的构建系统真的很烂。它与标准的基于 make 的项目有很大的不同,并且文档记录很差。但这就是 Android 提供的,所以这就是你必须使用的。 Eclipse 的 Android 原生支持就是围绕它构建的。


如果有兴趣,这里是包装头文件的样子。您可以使用javah 从您的 DEX 文件(已编译的 Java 类)生成它。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_cryptopp_prng_PRNG */

#ifndef _Included_com_cryptopp_prng_PRNG
#define _Included_com_cryptopp_prng_PRNG
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_cryptopp_prng_PRNG
 * Method:    CryptoPP_Reseed
 * Signature: ([B)I
 */
JNIEXPORT jint JNICALL Java_com_cryptopp_prng_PRNG_CryptoPP_1Reseed
  (JNIEnv *, jclass, jbyteArray);

/*
 * Class:     com_cryptopp_prng_PRNG
 * Method:    CryptoPP_GetBytes
 * Signature: ([B)I
 */
JNIEXPORT jint JNICALL Java_com_cryptopp_prng_PRNG_CryptoPP_1GetBytes
  (JNIEnv *, jclass, jbyteArray);

#ifdef __cplusplus
}
#endif
#endif

【讨论】:

  • 我通过这篇文章以及我使用的总代码和流程获得了帮助......所以它很有帮助
  • @Neha Shukla,如何仅从命令提示符编译 .so 文件?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 2017-11-02
  • 1970-01-01
  • 1970-01-01
  • 2013-04-16
  • 2017-03-13
相关资源
最近更新 更多