今天在安装及使用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
通过观察发现main函数确实重定义了,通过nm与grep命令组合的方式,确定main函数在main.o中。因此第一个想法是把main.o从libf2c.a中删除,使用如下命令:
ar -dv libf2c.a main.o
结果如下:
d - main.o
代表被删除的模块。而后再次运行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 );
^
/tmp/ccWCXPdq.o:在函数‘main’中:
my_test_lapack.c:(.text+0x229):对‘dgesvd_’未定义的引用
collect2: error: ld returned 1 exit status
发现dgesvd函数仍然未定义,同样使用nm与grep命令相结合的方式,查找dgesvd函数的实现,在lapack_LINUX.a找到相关定义,结果如下:
dgesvd.o:
0000000000000000 T dgesvd_
发现dgesvd确实已经实现了,直接使用“对‘dgesvd_’未定义的引用”进行搜索,结果发现这篇博客中介绍的方法: http://www.linuxdiyf.com/linux/16754.html
原来是文件依赖顺序的问题,因此修改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
好问题来了,要是我们把main.o加回到libf2c.a中会出现什么情况,使用命令如下:
首先使用“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,并帮我解决问题。