无法使用静态内部创建共享库

时间:2011-09-07 10:56:11

标签: android static shared android-ndk

请帮助我搜索整个互联网,但我找不到答案...

C层

我创建了简单的函数int mean(int, int);并将其放在 calc_mean.h 中并在 calc_mean.c 中初始化它是这两个文件。

calc_mean.c

#include "calc_mean.h"

int mean(int a, int b)  
{  
return (a+b) / 2;  
}  

calc_mean.h

int mean(int, int);

然后我使用以下make文件创建make文件并构建名为Test_Archive.a的存档(.a)文件

生成文件

GCC := C:\Tools\ndk-toolchain\ndk-standalone\bin\arm-linux-androideabi-gcc.exe
GPP := C:\Tools\ndk-toolchain\ndk-standalone\bin\arm-linux-androideabi-g++.exe
AR  := C:\Tools\ndk-toolchain\ndk-standalone\bin\arm-linux-androideabi-ar.exe

default: all

all: obj
    $(AR) r Test_Archive.a *.o

obj:
    $(GPP) -c *.c

我获得 Test_Archive.a 存档文件。现在我想将这个存档文件添加到JNI并从我的JNI项目中调用mean函数,因为我创建了JNI和Java文件,您可以在下面看到。


JAVA Layer

如何在java层中看到我有一个名为JMean的本地方法的TestJavaClass,此方法有两个int参数,并返回int

public class TestJavaClass
{
    /** Default Constructor
     * 
     */
    public TestJavaClass( ) {

    }

    /** Test Function. 
     *  
     * @param a
     * @param b
     * @return
     */
    public native int JMean( int a, int b);
}

JNI图层

这是JNI头文件

Test_Library.h

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

#ifndef _Included_com_Fido_OSTXLib_OSTX
#define _Included_com_Fido_OSTXLib_OSTX
#ifdef __cplusplus
extern "C" {
#endif

/*
 * Class:     com_Fido_OSTXLib_OSTX
 * Method:    JMean
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_Fido_OSTXLib_OSTX_JMean
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

Test_Library.c

#include "Test_Library.h"
#include "calc_mean.h"

JNIEXPORT jint JNICALL Java_com_Fido_OSTXLib_OSTX_JMean( JNIEnv* env, jobject thiz, jint a, jint b )
{
    return mean( a, b );
}

我把这两个文件 Test_Library.h Test_Library.c calc_mean.h Test_Archive.a 并创建make文件 Android.mk

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE           := Test_Library
LOCAL_SRC_FILES        := Test_Library.c

LOCAL_LDLIBS := -LTest_Archive.a

include $(BUILD_SHARED_LIBRARY)

但是当我想创建.so文件时,会出现以下错误,为什么?

  

$ ../../ndk-build Compile thumb:Test_Library&lt; = Test_Library.c   SharedLibrary:libTest_Library.so   C:/cygwin/home/android-ndk-r5b/Fido/ProjectOSTX/obj/local/armeabi/objs/OSTX_Library/OSTX_Library.o:   在函数Java_com_Fido_OSTXLib_OSTX_JMean': C:/cygwin/home/android-ndk-r5b/Fido/ProjectOSTX/jni/OSTX_Library.c:6: undefined reference to中,'collect2:ld返回1退出状态make: *   [/home/android-ndk-r5b/Fido/ProjectOSTX/obj/local/armeabi/libOSTX_Library.so]   错误1

为什么未定义对'mean'的引用?

3 个答案:

答案 0 :(得分:1)

以下是我成功构建代码所做的工作:

  1. 在Eclipse Android项目中创建文件夹jni

  2. 将文件calc_mean.c; calc_mean.h; Test_Library.c and Android.mk添加到jni文件夹

  3. 从Test_Library.c文件中删除行#include "Test_Library.h"。其他所有东西都可以保持不变。

  4. 在cygwin命令行中,转到Eclipse Android项目的根文件夹并运行ndk-build

  5. 如果您想在ndk构建过程中将calc_mean也构建为静态库,那么您可以按如下方式更改Android.mk文件:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE           := Test_Archive
    LOCAL_SRC_FILES        := calc_mean.c
    
    # compiler flags.
    LOCAL_LDLIBS   = -lz -lm
    LOCAL_CFLAGS   = -Wall -pedantic -std=c99 -g
    
    include $(BUILD_STATIC_LIBRARY)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := Test_Library
    LOCAL_STATIC_LIBRARIES := Test_Archive
    LOCAL_SRC_FILES := Test_Library.c
    
    
    include $(BUILD_SHARED_LIBRARY)
    

答案 1 :(得分:1)

正如我所说的主要原因是编译器设置,我在 makefile 中进行了一些修改,我的.a存档链接到共享库,这里有修改。

GCC := C:\Tools\ndk-toolchain\ndk-standalone\bin\arm-linux-androideabi-gcc.exe
GPP := C:\Tools\ndk-toolchain\ndk-standalone\bin\arm-linux-androideabi-g++.exe
AR  := C:\Tools\ndk-toolchain\ndk-standalone\bin\arm-linux-androideabi-ar.exe

OPTIONS  :=\
-fpic \
-ffunction-sections \
-funwind-tables  \
-fstack-protector \
-D__ARM_ARCH_5__ \
-D__ARM_ARCH_5T__ \
-D__ARM_ARCH_5E__ \
-D__ARM_ARCH_5TE__ \
-Wno-psabi \
-march=armv5te \
-mtune=xscale \
-msoft-float \
-mthumb \
-Os \
-fomit-frame-pointer \
-fno-strict-aliasing \
-finline-limit=64 \
-DANDROID \
-Wa, \
-O2 \
-DNDEBUG \
-g \

default: all


all: obj
    $(AR) r libtestlibrary.a *.o

obj:
    $(GCC) $(OPTIONS) -c *.c

答案 2 :(得分:1)

只需使用C编译器!

使用C ++编译器编译(Makefile具有“$(GPP)-c * .c”),函数符号名称包含参数信息,称为不同:不是“mean”,而是更复杂,类似于Java名称内部符号。您可以使用“nm”查看目标文件中的内容。

例如 my g ++生成:

# nm x.o
00000000 T _Z4meanii

所以没有“卑鄙”(但“Z4meanii”)。使用C编译器,符号名称很简单:

# nm x.o
00000000 T mean

(请注意,编译了相同的源代码内容)

所以改变Makefile:

obj:
    $(GCC) -c *.c

如果出于某种原因必须使用C ++编译器 ,则必须添加extern“C”:

calc_mean.h (简化,没有包含警卫等)

#ifdef __cplusplus
extern "C" {
#endif

int mean(int, int);

#ifdef __cplusplus
} // extern "C"
#endif

通常,如果在C ++文件中需要C符号名称,请使用extern“C”。 Test_Library.h正确使用它并提供了一个很好的例子。您可以将相同的extern“C”逻辑(最好包括#ifdef __cplusplus块)添加到头文件中。有些人认为总是这样做是好习惯。

但是请注意,C和C ++之间有几个,有时是微妙的差异,所以我建议使用C编译器编译C源代码,尽管我知道使用C ++编译器会有优势。

OKI,

斯特芬