今天在安装及使用CLAPACK的过程中,遇到诸多问题,现就遇到的问题及解决方式做简单记录,楼主的CLAPACK版本为3.2.1,操作系统为ubuntu 15.04,编译器为默认版本。
在安装CLAPACK的过程中,应对程序的源码做简单分析。根据源码中给出的安装手册中给出的说明手册,/BLAS/SRC 文件夹下给出了 BLAS 的程序源码,SRC文件夹下给出了CLAPACK的程序源码,/F2CLIBS/libf2c 文件夹下存放的是f2c库的程序源码。以上三部分源码会被分别编译为blas_LINUX.a、lapack_LINUX.a、libf2c.a,三个静态库的依赖关系依次为lapack_LINUX.a -> blas_LINUX.a -> libf2c.a,lapack中会调用位于blas中的函数,而blas中会调用libf2c中的函数,具体的分析过程也会给出。
好了,现在给出详细的安装过程,主要参考源码包中的README.install文件
1)解压缩并制作make.inc
解压缩命令:gunzip clapack.tgz;tar xvf clapack.tar
制作make.inc:由于makefile中包含的是make.inc,而当前软件包中给出的是make.inc.example,因此将make.inc.example根据机器的实际情况进行修改,实际情况就是,楼主根本不需要任何修改,直接就改为了make.inc。
2)在根目录下 make f2clib,这一步没有任何问题,产生libf2c.a为静态库。
3)在根目录下 make blaslib ,这一步可选,可选用其他blas库,推荐使用blaslib,主要由于其安装方便,产生blas_LINUX.a。若选用其他blas库,则需要make cblaswrap,不过这一步楼主并没有实践,因此有兴趣的同学可以自行摸索。
4)在根目录下make,至此安装过程全部完成,产生lapack_LINUX.a。
安装完成后就要使用clapack,clapack 作为一套静态链接库,在使用过程直接链接即可。因此首先编写测试代码,所使用的测试代码来自于以下地址:http://www.netlib.org/clapack/faq.html#1.4 1.9节。
代码如下:
/* Start of Listing */ #include "f2c.h" #include "stdio.h" #include "clapack.h" #define SIZE 4 main( ) { char JOBU; char JOBVT; int i; integer M = SIZE; integer N = SIZE; integer LDA = M; integer LDU = M; integer LDVT = N; integer LWORK; integer INFO; integer mn = min( M, N ); integer MN = max( M, N ); double a[SIZE*SIZE] = { 16.0, 5.0, 9.0 , 4.0, 2.0, 11.0, 7.0 , 14.0, 3.0, 10.0, 6.0, 15.0, 13.0, 8.0, 12.0, 1.0}; double s[SIZE]; double wk[201]; double uu[SIZE*SIZE]; double vt[SIZE*SIZE]; JOBU = 'A'; JOBVT = 'A'; LWORK = 201; /* Subroutine int dgesvd_(char *jobu, char *jobvt, integer *m, integer *n, doublereal *a, integer *lda, doublereal *s, doublereal *u, integer * ldu, doublereal *vt, integer *ldvt, doublereal *work, integer *lwork, integer *info) */ dgesvd_( &JOBU, &JOBVT, &M, &N, a, &LDA, s, uu, &LDU, vt, &LDVT, wk, &LWORK, &INFO); printf("\n INFO=%d", INFO ); for ( i= 0; i< SIZE; i++ ) { printf("\n s[ %d ] = %f", i, s[ i ] ); } return 0; } /* End of Listing */
根据安装说明,程序在链接时需要使用的静态库有blas_LINUX.a、lapack_LINUX.a、libf2c.a,但在编译libf2c.a时发现其中有main函数,测试程序中同样具有main函数,如果直接编译会出现main函数重定义的情况,因此先试着写了一个makefile看是否还存在其他问题,makefile如下,其实只有一句话。
gcc -o my_test_lapack -I./INCLUDE -L./ lapack_LINUX.a blas_LINUX.a libf2c.a -lm my_test_lapack.c
my_test_lapack.c: In function ‘main’: my_test_lapack.c:48:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘integer’ [-Wformat=] printf("\n INFO=%d", INFO ); ^ /tmp/ccLtDGCS.o:在函数‘main’中: my_test_lapack.c:(.text+0x0): `main'被多次定义 libf2c.a(main.o):(.text.startup+0x0):第一次在此定义 libf2c.a(main.o):在函数‘main’中: (.text.startup+0x87):对‘MAIN__’未定义的引用 /tmp/ccLtDGCS.o:在函数‘main’中: my_test_lapack.c:(.text+0x229):对‘dgesvd_’未定义的引用 collect2: error: ld returned 1 exit status
ar -dv libf2c.a main.o
d - main.o
结果如下:
my_test_lapack.c: In function ‘main’: my_test_lapack.c:48:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘integer’ [-Wformat=] printf("\n INFO=%d", INFO ); ^ /tmp/ccWCXPdq.o:在函数‘main’中: my_test_lapack.c:(.text+0x229):对‘dgesvd_’未定义的引用 collect2: error: ld returned 1 exit status
dgesvd.o: 0000000000000000 T dgesvd_
原来是文件依赖顺序的问题,因此修改makefile文件为:
gcc -o my_test_lapack my_test_lapack.c -I./INCLUDE -L./ lapack_LINUX.a blas_LINUX.a libf2c.a -lm
INFO=0 s[ 0 ] = 34.000000 s[ 1 ] = 17.888544 s[ 2 ] = 4.472136 s[ 3 ] = 0.000000
首先使用“ar -t libf2c.a”命令查看obj文件顺序,发现f77vers.o是第一个文件。
然后使用
ar -rbv f77vers.o libf2c.a main.o
命令将main.o重新加入到libf2c.a,并运行makefile,结果如下:
my_test_lapack.c: In function ‘main’: my_test_lapack.c:48:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘integer’ [-Wformat=] printf("\n INFO=%d", INFO ); ^
INFO=0 s[ 0 ] = 34.000000 s[ 1 ] = 17.888544 s[ 2 ] = 4.472136 s[ 3 ] = 0.000000
不知道大神有没有时间完整的看完这篇blog,并帮我解决问题。