【问题标题】:ndk-build outputs ‘error adding symbols. File in wrong format’ndk-build 输出“添加符号时出错。文件格式错误’
【发布时间】:2015-08-19 06:52:17
【问题描述】:

我想在我的 Android 项目中使用用 C++ 编写的 exiv2 库。为此,我尝试使用 Android NDK 交叉编译库。

对于交叉编译,我遵循以下步骤:

  1. 将ndk路径添加到变量PATH

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

    ./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. 构建静态库和足够的headers

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

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

    ├── 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 info
LOCAL_MODULE := exiv2
LOCAL_SRC_FILES := ../prebuild/libexiv2.a
LOCAL_EXPORT_C_INCLUDES := ../prebuild/include/
LOCAL_EXPORT_LDLIBS := -lz
include $(PREBUILT_STATIC_LIBRARY)


#wrapper info
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

我认为交叉编译中的标志有问题。我已经尝试了几个选项,但仍然有问题。 我遵循了这些指示:https://groups.google.com/forum/#!topic/android-ndk/mYh1LzMu_0U

【问题讨论】:

    标签: android c++ android-ndk exiv2


    【解决方案1】:

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

    不使用 ndk-build 的交叉编译很难在 Android 上正确运行,尤其是因为您不仅应该支持 armv5,还应该支持 armv7、x86、x86_64、arm64-v8a...

    您应该首先将--platform 选项设置为与您的最低 SDK 级别相同的级别。然后重建您的库并将其放在../prebuild/armeabi 下。 然后为 x86 架构交叉编译你的 lib:

    ./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 info
    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 info
    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 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*, ...)'
    • 我使用了错误的 gcc 版本。它适用于 4.8。
    • 此解决方案假定旧版 ndk gradle 构建。使用新的 gradle-experimental 构建系统,没有 Application.mk
    • 最初的问题是关于 ndk-build,所以答案仍然准确。如果您对 gradle 和实验性插件有同样的问题,您应该打开一个新问题。
    猜你喜欢
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-26
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    相关资源
    最近更新 更多