0

我是 C 编码的新手,但我编写了一个用于模拟神经网络的 Matlab 程序,我希望将其转换为 C 代码,因为我们的超级计算机集群不允许同时运行多个 Matlab 模拟。为此,我找到了 GotoBLAS 来处理矩阵数学。

不幸的是,我不确定如何使用它,因为我在 C 和使用外部库方面没有很多经验。我假设'dgemm'是GotoBLAS中的一个函数,来自阅读BLAS指南pdf。我已经能够成功编译 GotoBLAS,但是当我这样做时:

gcc -o outputprog main.c -Wall -L -lgoto2.a

我收到以下消息:

undefined reference to 'dgemm'

据我了解,我应该包含.h来自 GotoBLAS 的一些文件(或者可能不包含),但我不确定是哪个文件(或者这是否正确)。

对此的任何帮助将不胜感激。如果需要更多信息,请告诉我。

4

2 回答 2

6

一个问题可能是该-L选项后面需要一个“目录”名称,因此gcc(或由 调用的链接器gcc)被-lgoto2.a视为目录。编译器不会抱怨不存在的目录;它只是忽略了它们。您希望在哪个目录中找到该库?(为了这个答案的目的,我假设它在/usr/local/lib.)

另一个问题可能是该库不称为 libgoto2.aa 或 libgoto2.a.so 或类似名称。您通常不会指定.a后缀。(出于此答案的目的,我假设该库是 libgoto2.a 或 libgoto2.so。)

看来您不需要指定标头的位置;这意味着它们位于一个足够常规的位置,编译器无论如何都会在那里查找。如果这是正确的,那么库也可能位于一个非常传统的位置,并且该-L选项可能是不必要的。

因此,您也许可以使用:

gcc -Wall -o outputprog main.c -lgoto2

或者您可能需要使用:

gcc -Wall -o outputprog main.c -L/usr/local/lib -lgoto2

在评论中进行了一些广泛的讨论之后,以及库在当前目录中并命名libgoto2.a并且符号dgemm仍然丢失的信息之后,我下载了 GotoBLAS2 版本 1.13并尝试在半支持的平台上编译它(MacOS X,可能假装是 Linux,具有 x86_64 架构)。构建并不完全成功 - 一些汇编代码中的问题。但是,在标题中四处寻找,似乎可以解决您的问题:

cblas.h

在此,在许多其他函数定义中,我们发现:

void cblas_dgemm(enum CBLAS_ORDER Order, enum CBLAS_TRANSPOSE TransA,
                 enum CBLAS_TRANSPOSE TransB, blasint M, blasint N, blasint K,
                 double alpha, double *A, blasint lda, double *B, blasint ldb,
                 double beta, double *C, blasint ldc);

标头中的所有函数符号都以 . 为前缀cblas_。您的代码应该使用:

#include "cblas.h"

您应该使用带有前缀的 Fortran 名称(小写)调用函数cblas_

cblas_dgemm(...);

并且要使用的正确链接线是上面列出的第一个选项:

gcc -Wall -o outputprog main.c -lgoto2

在紧要关头,您可以定义宏以将常规(无前缀)名称映射到正确的 C 函数名称,但我不相信这是值得的:

#define DGEMM cblas_dgemm

或(更安全,因为它检查参数列表的长度,但更详细):

#define DGEMM(a,b,c,d,e,f,g,h,i,j,k,l,m,n) cblas_dgemm(a,b,c,d,e,f,g,h,i,j,k,l,m,n)

然后你可以写:

DGEMM(a, ..., n);

并且将调用正确的函数。


对上述部分成功构建的 GotoBLAS2 的实验表明:

  • cblas.h不是独立的(与良好的编码标准相反)。
  • common.h必须包含在它之前。
  • common.h包括许多其他标题:
    • 配置文件
    • common_x86_64.h
    • 参数.h
    • common_param.h
    • common_interface.h
    • common_macro.h
    • common_s.h
    • common_d.h
    • common_q.h
    • common_c.h
    • common_z.h
    • common_x.h
    • common_level1.h
    • common_level2.h
    • common_level3.h
    • common_lapack.h
  • 以下代码有可能与完整的库链接:

    #include "common.h"
    #include "cblas.h"
    
    void check_dgemm(void)
    {
        double A[33] = { 0.0 };
        double B[33] = { 0.0 };
        double C[33] = { 0.0 };
        cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
                    3, 3, 3, 2.0, A, 3, B, 3, 3.0, C, 3);
    }
    
    int main(void)
    {
        check_dgemm();
        return 0;
    }
    

    (在我公认的损坏的库构建中,投诉从“cblas_dgemm()找不到”到缺少许多其他功能。这是一个巨大的改进!)

于 2011-09-01T05:43:40.933 回答
3

好的,我能够在 GotoBLAS 邮件列表https://lists.tacc.utexas.edu/mailman/listinfo/gotoblas上找到答案(据我所见,该邮件未在网站上列出)。这是使用 GotoBLAS2 和 C 和 GCC 编译器的快速一步一步。

构建 GotoBLAS2 库(.so 和 .a),库中有很好的文档,所以我不会在这里发布。将这两个文件都包含在您选择的 libs 目录中,由 -L 设置。我只包括一个,因为我认为它们只是同一个库的不同版本,这是不正确的。

-lgfortran如果你想用 gcc 编译, 也可以链接到。-lpthread可能也很有用,虽然我不确定,但我已经看到了它的例子,但它没有编译。你的 gcc 应该是这样的:

gcc -Wall -o outprog -L./GotoLIBSDIR -lgoto2 -lgfortran -lpthread(maybe) main.c

最后,调用function_()而不是function(),例如,dgemm_()当使用 gfortran 编译 fortran 接口时。

作为 fortran 接口的替代方案,cblas 接口可以用作cblas_dgemm(). 您仍然需要为此链接到-lgfortran,否则链接到libgoto2.so将失败,并且您需要链接到该文件才能cblas_dgemm()正确使用。

似乎不需要包含任何 .h 文件或其他任何内容。

希望其他人会发现这很有用。感谢所有的帮助!

于 2011-09-01T23:47:40.067 回答