2012-01-09 31 views
0

我嘗試開發一個Android應用程序。我已經設法使用NDK實現一個相當小的C++函數。但是現在我想使用我在Google Docs上找到的一個非常大的C++庫。 當我現在嘗試用NDK的構建工具,構建它,我得到這個錯誤在Cygwin的控制檯:NDK對{extern「C」函數}的未定義引用?

Compile++ thumb : ndkfoo <= subspace.cpp 
Compile++ thumb : ndkfoo <= classifier.cpp 
Compile++ thumb : ndkfoo <= eigen.cpp 
Compile++ thumb : ndkfoo <= image.cpp 
Compile++ thumb : ndkfoo <= imageio.cpp 
Compile++ thumb : ndkfoo <= local.cpp 
Compile++ thumb : ndkfoo <= matrix.cpp 
Compile++ thumb : ndkfoo <= sample.cpp 
SharedLibrary : libndkfoo.so 
./obj/local/armeabi/objs/ndkfoo/eigen.o: In function `LibSubspace::geneigen(doub 
le*, double*, int, double*, int, bool)': 
U:\workspace\test/jni/eigen.cpp:91: undefined reference to `ilaenv_' 
U:\workspace\test/jni/eigen.cpp:96: undefined reference to `dsygv_' 
U:\workspace\test/jni/eigen.cpp:128: undefined reference to `dggev_' 
./obj/local/armeabi/objs/ndkfoo/eigen.o: In function `LibSubspace::eigen(double* 
, double*, double*, int, bool)': 
U:\workspace\test/jni/eigen.cpp:55: undefined reference to `ilaenv_' 
U:\workspace\test/jni/eigen.cpp:58: undefined reference to `dsyev_' 
collect2: ld returned 1 exit status 
make: *** [obj/local/armeabi/libndkfoo.so] Error 1 

這個函數的代碼是如下:

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <float.h> 
#include <assert.h> 
#include <string.h> 

#include "eigen.h" 

extern "C" int ilaenv_(int *ispec, const char *name__, const char *opts, 
    int *n1, int *n2, int *n3, int *n4, int name_len, int opts_len); 

extern "C" int dsyev_(const char *jobz, const char *uplo, int *n, double *a, 
    int *lda, double *w, double *work, int *lwork, 
    int *info); 

extern "C" int dsygv_(int *itype, const char *jobz, const char *uplo, int * 
    n, double *a, int *lda, double *b, int *ldb, 
    double *w, double *work, int *lwork, int *info); 

extern "C" int dggev_(const char *jobvl, const char *jobvr, int *n, double * 
    a, int *lda, double *b, int *ldb, double *alphar, 
    double *alphai, double *beta, double *vl, int *ldvl, 
    double *vr, int *ldvr, double *work, int *lwork, 
    int *info); 

namespace LibSubspace { 

int eigen(double* A, double* V, double* E, int n, bool verbose) { 
    int info; 
    int ispec = 1; 
    int lwork; 

    lwork = (ilaenv_(&ispec,"DSYEV","U",&n,&n,&n,&n,5,1)+2)*n; 
    double *work = (double *)malloc(lwork*sizeof(double)); 
    memcpy(V,A,n*n*sizeof(double)); 
    dsyev_("V","U",&n,V,&n,E,work,&lwork,&info); 
    free(work); 

    //check the return value 
    if(info!=0) { 
     if(verbose) { 
      printf("Error computing eigenvectors: "); 
      if(info>0) { 
       printf("Algorithm failed to converge\n"); 
      } else if(info<0) { 
       printf("Illegal argument\n"); 
      } else { 
       printf("Unknown error\n"); 
      } 
     } 
     return 0; 
    } 

    return 1; 
} 


int geneigen(double *A, double *B, int n, double *W, int algorithm, 
      bool verbose) { 
    //getting the optimal lwork 
    int ispec = 1; 
    int lwork; 
    int info; 

    switch(algorithm) { 

     case EIGEN_CHOL: 
     { 
      //computing eigenvectors 
      lwork = (ilaenv_(&ispec,"DSYGV","U",&n,&n,&n,&n,5,1)+2)*n; 
      double *work = (double *)malloc(lwork*sizeof(double)); 
      int problemType = 1; 
      char job = 'V'; 
      char uplo = 'U'; 
      dsygv_(&problemType,&job,&uplo,&n,A,&n,B,&n,W,work,&lwork,&info); 

      free(work); 

      //check the return value 
      if(info!=0) { 
       if(verbose) { 
        printf("Error computing eigenvectors: "); 
        if(info>n) { 
         printf("Matrix B is not positive definite\n"); 
        } else if(info<=n) { 
         printf("The problem failed to converge\n"); 
        } else if(info<0) { 
         printf("Illegal argument\n"); 
        } else { 
         printf("Unknown error\n"); 
        } 
       } 
       return 0; 
      } 
     } 
     break; 

     case EIGEN_QZ: 
     { 
      //more general algorithm 
      double *alphar = (double *)malloc(n*sizeof(double)); 
      double *alphai = (double *)malloc(n*sizeof(double)); 
      double *beta = (double *)malloc(n*sizeof(double)); 
      double *VR = (double *)malloc(n*n*sizeof(double)); 
      lwork = 8*n; 
      double *work = (double *)malloc(lwork*sizeof(double)); 
      dggev_("N","V",&n,A,&n,B,&n,alphar,alphai,beta, 
            NULL,&n,VR,&n,work,&lwork,&info); 
      //eigenvalues 
      for(long i=0;i<n;i++) { 
       if(beta[i]!=0) { 
        W[i] = alphar[i]/beta[i]; 
       } else W[i] = 0; 
      } 
      //eigenvectors 
      for(long i=0;i<n;i++) { 
       for(long j=0;j<n;j++) { 
        A[i*n+j] = VR[i*n+j]; 
       } 
      } 
      free(alphar); 
      free(alphai); 
      free(beta); 
      free(VR); 
      free(work); 

      if(info!=0) { 
       printf("Error computing eigenvectors: "); 
       if(info<0) { 
        printf("Illegal argument\n"); 
       } else if(info<=n) { 
        printf("QZ iteration failed\n"); 
       } else { 
        printf("Unknown error\n"); 
       } 
       return 0; 
      } 
     } 
     break; 

    } 

    return 1; 
} 

} //namespace 

不幸的是我是絕對不明白爲什麼發生這些錯誤。我對C++並不熟悉,這就是爲什麼我想使用NDK,希望不必更改現有庫的任何內容。

+2

這些是鏈接器錯誤,而不是編譯器錯誤。您需要爲鏈接器命令指定相關的庫。 – 2012-01-09 14:04:42

+0

我有沒有在Android.mk中做到這一點?我認爲ndk-build工具會自動完成鏈接:( – Matthias 2012-01-09 14:12:03

+0

那麼,無論你從哪裏獲得這四個函數,都必須在鏈接時提供,但是你可以檢查實際的鏈接器調用,看看是否所有東西都是如你所期望的那樣,並且仔細檢查函數聲明,如果你也是爲那些來自庫的人設計的。 – 2012-01-09 14:18:24

回答

0

Google告訴我這些函數來自Fortran-to-C編譯器的運行時。所以你需要鏈接一個名爲libf2c的庫,或者找到源代碼並將它們也作爲NDK項目的一部分。後者聽起來像是一個更有希望的方法 - 我不認爲現成的NDK構建存在。

+0

好吧,聽起來像我應該首先檢查這個C++項目是否運行,我試着用visula studio編譯它,看看它是否工作,如果沒有,我會嘗試lib2fc反正會告訴你:) 感謝迄今。 – Matthias 2012-01-09 15:05:26