ndk-build 输出“错误添加符号。文件格式不正确”。

10

我想在我的Android项目中使用用C++编写的exiv2库。为了做到这一点,我尝试使用Android NDK交叉编译该库。

为了进行交叉编译,我遵循以下步骤:

  1. 将NDK路径添加到PATH变量中

    PATH="/home/patrycja/android-packages/ndk:${PATH}"
    export PATH
    
  2. 安装用于交叉编译C/C++的标准工具链。

    ./make-standalone-toolchain.sh --platform=android-21 --install-dir=/tmp/my-android-toolchain --ndk-dir='/home/patrycja/android-packages/ndk/' --toolchain=arm-linux-androideabi-4.9 --system=linux-x86_64
    

    输出:

    Copying prebuilt binaries...
    Copying sysroot headers and libraries...
    Copying c++ runtime headers and libraries...
    Copying files to: /tmp/my-android-toolchain
    Cleaning up...
    Done.
    
  3. 设置一些环境变量,以便配置和构建过程使用正确的编译器。

    export PATH=/tmp/my-android-toolchain/bin:$PATH
    export CC="arm-linux-androideabi-gcc"
    export CXX="arm-linux-androideabi-g++"
    export CFLAGS='-mthumb -O2'
    export CXXFLAGS='-mthumb -O2'
    export LDFLAGS='-Wl,--fix-cortex-a8'
    export LIBS='-lstdc++ -lsupc++'
    
  4. 构建静态库和足够的头文件

    ./configure --prefix=$(pwd)/build --host=arm-linux-androideabi --disable-shared --disable-xmp --disable-nls
    

因此,我创建了“build”类别的文件:

    ├── bin
    │   └── exiv2
    ├── include
    │   └── exiv2
    │       ├── *.hpp
    │
    ├── lib
    │   ├── libexiv2.a
    │   ├── libexiv2.la
    │   └── pkgconfig
    │       └── exiv2.pc
    └── share
        └── man
            └── man1
                └── exiv2.1

我将创建的静态库libexiv2.ainclude文件夹复制到了我的Android项目中的appName/src/main/jni/prebuild目录下。

Android.mk文件如下:

LOCAL_PATH := $(call my-dir)

# Static library information
LOCAL_MODULE := exiv2
LOCAL_SRC_FILES := ../prebuild/libexiv2.a
LOCAL_EXPORT_C_INCLUDES := ../prebuild/include/
LOCAL_EXPORT_LDLIBS := -lz
include $(PREBUILT_STATIC_LIBRARY)

# Wrapper information
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../prebuild/include/
LOCAL_MODULE    := helloJNI
LOCAL_SRC_FILES := helloJNI.cpp
LOCAL_STATIC_LIBRARIES := exiv2
include $(BUILD_SHARED_LIBRARY)

在我的Android封装中,我尝试使用这个库。代码如下:
#include <string.h>
#include <jni.h>
#include <exiv2/exiv2.hpp>

extern "C" {

JNIEXPORT jstring JNICALL Java_com_example_patrycja_testndi2_MyActivity_helloJNI(JNIEnv *env, jobject thiz)
    {
        std::ostringstream os;
        std::string file("/storage/emmc/DCIM/100MEDIA/IMAG0021.jpg");
        Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file);
        return env->NewStringUTF("asldjaljd");
    }
}

然而ndk-build输出说找不到它。

[arm64-v8a] Compile++      : helloJNI &lt;= helloJNI.cpp
[arm64-v8a] SharedLibrary  : libhelloJNI.so
jni/../prebuild/libexiv2.a: error adding symbols: File in wrong format
collect2: error: ld returned 1 exit status
make: *** [obj/local/arm64-v8a/libhelloJNI.so] Error 1

我认为交叉编译中的参数存在问题。我尝试了几个选项,但仍有问题。

我遵循了这些指示:如何在本机 Android 代码中使用外部 C++ 库

1个回答

8

您已经为至少运行Android 5.0(棒棒糖)的armv5+设备编译了exiv2。在这里,ndk-build失败了,因为它试图从正在构建的arm64-v8a库中链接它。

在Android上进行交叉编译而不使用ndk-build很难做到正确,特别是因为您不仅应该支持armv5,还应该支持armv7、x86、x86_64、arm64-v8a等。

您应该首先将--platform选项设置为与最低SDK级别相同的级别。然后重新构建您的库并将其放置在../prebuild/armeabi下。

然后还要为x86架构交叉编译您的库:

./make-standalone-toolchain.sh --platform=android-9 --install-dir=/tmp/my-android-toolchain-x86 --ndk-dir='/home/patrycja/android-packages/ndk/' --arch=x86 --toolchain=x86-4.8 --system=linux-x86_64

export PATH=/tmp/my-android-toolchain-x86/bin:$PATH
export CC="i686-linux-android-gcc"
export CXX="i686-linux-android-g++"
export CFLAGS='-O2 -mtune=atom -mssse3 -mfpmath=sse'
export CXXFLAGS='-O2 -mtune=atom -mssse3 -mfpmath=sse'
export LDFLAGS=''
export LIBS='-lstdc++ -lsupc++'

./configure --prefix=$(pwd)/build-x86 --host=x86 --disable-shared --disable-xmp --disable-nls

将创建的 .a 移动到 ../prebuild/x86

理想情况下,您还应该为 armeabi-v7a、mips、mips64 和 arm64-v8a 重复相同的过程。

最后,您可以使用 TARGET_ARCH_ABI 变量在 Android.mk 中包含正确的 .a,如下所示:

LOCAL_PATH := $(call my-dir)

# Static library information
LOCAL_MODULE := exiv2
LOCAL_SRC_FILES := ../prebuild/$(TARGET_ARCH_ABI)/libexiv2.a
LOCAL_EXPORT_C_INCLUDES := ../prebuild/include/
LOCAL_EXPORT_LDLIBS := -lz
include $(PREBUILT_STATIC_LIBRARY)

# Wrapper information
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../prebuild/include/
LOCAL_MODULE    := helloJNI
LOCAL_SRC_FILES := helloJNI.cpp
LOCAL_STATIC_LIBRARIES := exiv2
include $(BUILD_SHARED_LIBRARY)

Application.mk文件中(如果不存在,请创建一个新文件),指定您支持的架构和您的最低目标平台:

APP_ABI := armeabi x86 # Ideally, this should be set to "all"
APP_PLATFORM := android-14 # Should be the same as -platform and your minSdkVersion.

我按照你说的做了,但是又出现了另一个问题。执行ndk-build时,我收到以下错误信息:jni/../prebuild/armeabi-v7a/libexiv2.a(pngchunk.o):pngchunk.cpp:function Exiv2::Internal::PngChunk::parseChunkContent(Exiv2::Image*, unsigned char const*, long, Exiv2::DataBuf): error: undefined reference to 'std::__throw_out_of_range_fmt(char const*, ...)' - rocksparrow
我使用了错误版本的gcc。它需要4.8版本才能正常工作。 - rocksparrow
2
这个解决方案假定使用传统的ndk gradle构建。在新的gradle-experimental构建系统中,没有Application.mk文件。 - IgorGanapolsky
2
原问题涉及到ndk-build,因此答案仍然准确。如果您在使用gradle和实验性插件时遇到了同样的问题,您应该开一个新的问题。 - ph0b

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接