无法在mac OS X

时间:2016-11-26 20:49:13

标签: c macos gcc blas

我正在尝试让a repository收集我在互联网上找到的C数学和代数库(BLAS,CBLAS,LAPACK,CLAPACK,LAPACKE,ATLAS,openblas,GSL)的所有示例,教程和说明。 ...)。但似乎我无法获得在mac OS X上运行的已编译的BLAS .a文件。

到目前为止,我已经能够编译BLAS并在ubuntu上使用它:

  1. 下载并编译netlib网站的BLAS源代码(将blas_LINUX.a重命名为libblas.a)
  2. 然后我可以使用以下命令在ubuntu上编译C文件:

    gcc foo.c path/to/libblas.a

  3. 在我的Mac OS X(EL Capitan)上,我可以编译BLAS(将make.inc中的LINUX更改为DARWIN),但是当我尝试使用上面的命令编译C代码时,我得到如下错误:

    Undefined symbols for architecture x86_64:
      "_ddot_", referenced from:
          _main in foo-3a35db.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    (“ ddot ”部分因不同功能而异)

    可能性:

    1. 也许我没有在mac上正确编译库,并且有一些我不知道的差异
    2. mac OS X的内置Accelerate框架搞乱了编译过程
    3. P.S。我知道BLAS / LAPACK已经内置到mac OS X Accelerate框架中,我可以使用命令gcc foo.c -lblasgcc foo.c -framework Accelerate轻松编译,但我想使用netlib编译的.a。我想知道为什么它在ubuntu上运行正常而不是mac OS X?

      P.S.2。请注意,我可以在mac OS X上成功编译源代码而没有任何错误。我只是可以使用它!

      示例代码:source

      #include <stdio.h>
      #include <stdlib.h>
      
      double ddot_(const int *N, const double *a, const int *inca, const double *b, const int *incb);
      
      int main(int argc, char **argv) {
        double *a = (double *)malloc(3 * sizeof(double));
        a[0] = 1.0;
        a[1] = 2.0;
        a[2] = 3.0;
        // on the stack
        double b[3] = {4.0, 5.0, 6.0};
      
        int N = 3, one = 1; // one really doesn't look good in C
      
        double dot_product = ddot_(&N, a, &one, b, &one);
        printf(" The dot product is: %f \n", dot_product);
      
        return 0;
      }
      

      (edit1)解决方案:

      1. 打开make.inc
      2. 将行OPTS = -O3更改为OPTS = -O3 -pipe -c并制作。
      3. (edit2):更好的解决方案: 既然我问了这个问题,我就意识到我做错了什么。 Netlib BLAS实际上是fortran例程/子例程/函数的集合。源代码中的Makefile只给我们一个静态库libblas.a,它是用gfortran编译的所有.o目标文件的集合。当我们想编译一个想要调用其中一个例程的C代码时,我们还需要链接到gfortran库libgfortran。*所以如果你安装了gcc(brew install gcc)。寻找libgfrotran *(sudo find / -name "libgfortrn.*"),然后将你的gcc链接到这个文件夹。为了方便我在这里放一个Makefile:

        all:
            gcc -c foo.c
            gcc -o bar.out foo.o -L path/to/libgfortran.*/ -lgfortran -L path/to/libblas.a -lblas
        

        或者用gfortran直接编译代码:

        all:
            gcc -c foo.c
            gfortran -o bar.out foo.o -L path/to/libblas.a -lblas
        

        或简单编译:

        gcc foo.c bar.out -L path/to/libblas.a -lblas -L path/to/libgfortran.*/ -lgfortran
        

        奇怪的是前者解决方案如何/为何真正起作用以及为什么在ubuntu上你不必链接到-lgfortran!

1 个答案:

答案 0 :(得分:0)

似乎你用Netlib编译了BLAS库,编译器选项改变了Fortran例程的修改方案。

默认情况下,Netlib的make.inc使用gfortran来编译BLAS:

$ grep FORTRAN make.inc
#  Modify the FORTRAN and OPTS definitions to refer to the
FORTRAN  = gfortran

它是在没有任何标志的情况下编译的:

gfortran -O3 -pipe -c ddot.f -o ddot.o

你得到了ddot()例程:

$ grep -i ddot ddot.o libblas.a 
Binary file ddot.o matches
Binary file libblas.a matches

您可以使用命令行工具找到它:

$ nm ddot.o libblas.a | grep -i ddot
ddot.o:
0000000000000000 T _ddot_
libblas.a(ddot.o):
0000000000000000 T _ddot_

您的示例使用库进行编译:

cc ex.c libblas.a

或使用ddot.o文件:

cc -pipe ex.c ddot.o

我无法重现你的问题。您应该使用nmgrep命令来查明ddot()例程名称的变化。

PS。在;的定义结束后,您的代码会有额外的分号main()