【问题标题】:Unable to use compiled netlib BLAS on mac OS X无法在 Mac OS X 上使用已编译的 netlib BLAS
【发布时间】:2016-11-26 20:49:12
【问题描述】:

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

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

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

    gcc foo.c path/to/libblas.a

在我的 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 框架搞乱了编译过程

附:我知道 BLAS/LAPACK 已经内置在 mac OS X Accelerate 框架中,我可以使用命令 gcc foo.c -lblasgcc foo.c -framework Accelerate 轻松编译,但我想使用来自 netlib 的已编译 .a。我想知道为什么它在 ubuntu 上可以正常工作,但在 mac OS X 上不行?

附注 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 并制作。

(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!

【问题讨论】:

    标签: c macos gcc blas


    【解决方案1】:

    看来您从 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() 的定义结束后有额外的分号 ;

    【讨论】:

    • 我想我设法使用您刚刚提供的标志解决了问题。似乎通过将标志 -pipe -c 添加到 make.inc 文件现在 BLAS 库已正确编译,我可以使用它来编译其他 C 代码。我要多尝试一下。我会在这里报告
    • 别担心-pipe(这意味着:不要在/tmp中创建临时文件,而是使用UNIX管道在编译器和链接器工具链之间进行通信)。 `-c' 标志仅表示 仅编译(不要链接或尝试创建可执行二进制文件)。
    • 是的,实际上我完全错了。我在帖子中添加了更多细节。你介意检查一下并告诉我它是否正确吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多