Reputation: 513
I need to use lapack and blas in my c++ code, I want to link either MKL, ACML, or default lapack and blas in linux systems. Unfortunately, they have different convention in c. For example, zdotc in MKL ( mkl_blas.h ) is
zdotc(&result, &n, x, &incx, y, &incy);
and call zdotc from default lapack and blas (fortran version) is:
result = zdotc_(&n, x, &incx, y, &incy);
If I want my code to use either MKL, ACML, or default lapack blas. I need to write a wrap for this:
#ifdef FORTRAN_NO_UNDERSCORE
#define F77NAME(x) x
#else
#define F77NAME(x) x##_
#endif
complex<double> zdotc_wrap(int n, const complex<double>*x, int incx, const complex<double>*y, int incy)
{
#if defined(USE_MKL)
complex<double> result;
zdotc(&result, &n, x, &incx, y, &incy)
return result;
#elif defined(USE_LAPACK_BLAS)
return F77NAME(zdotc)(&n, x, &incx, y, &incy);
#elif defined(USE_ACML)
...
#endif
}
While there are so many functions, it costs time to write wraps for each of them. I hope there is one unique convention of them. If you are using lapack and blas in your code, how do you solve this problem? Do you have a wrap for all the functions? If there is a wrap, it will be great if you can share that with me.
Update:
I find one way to solve this problem:
#ifndef FORTRAN_COMPLEX_FUNCTIONS_RETURN_VOID
extern complex<double> zdotc(
#else
extern void zdotc(complex<double>* retval,
#endif
const int *n,
const complex<double> *zx,
const int *incx,
const complex<double> *zy,
const int *incy
);
Then I can call this function by:
complex<double> result;
#ifndef FORTRAN_COMPLEX_FUNCTIONS_RETURN_VOID
result = zdotc(
#else
zdotc(&result,
#endif
&n, x, &incx, y, &incy);
Any suggestions? Better solutions? Thank you for your help.
Upvotes: 3
Views: 2361
Reputation: 2012
Vendor supplied BLAS and LAPACK implementations usually include symbols with the trailing underscore, because that is how Fortran 77 compilers worked originally. The modern gfortran behavior is to also add the trailing underscore for compatibility, but there is the -fno-underscoring
option to turn it off.
For code you compile yourself with gfortran such as the reference BLAS and LAPACK, you can choose whether to return complex values directly or by using the indirect result
pointer argument. To get the indirect behavior, compile with -ff2c
. The default gfortran behavior is to return complex values directly.
The simplest way to avoid the macros and wraps in your code is to assume trailing underscores in the names and indirect return values for complex results in an added first argument. That will be compatible with vendor libraries. Then compile BLAS and LAPACK with -ff2c
to make it work there.
For maximum flexibility you can use wrap functions. Within the wrapper you should only need to worry about whether complex arguments are returned directly or not, you should not need special handling for each different library.
complex<double> zdotc_wrap(int n, const complex<double>*x, int incx, const complex<double>*y, int incy)
{
#if defined(FORTRAN_COMPLEX_FUNCTIONS_RETURN_VOID)
complex<double> result;
zdotc_(&result, &n, x, &incx, y, &incy);
return result;
#else
return zdotc_(&n, x, &incx, y, &incy);
#endif
}
In BLAS there are only a handful of functions that need to be wrapped: CDOTU CDOTC ZDOTU ZDOTC
. In LAPACK there are just CLADIV ZLADIV
(I think).
Upvotes: 2
Reputation: 1624
I am using lapack in my c++ code and I haven't had that issue. You can check the cosmo++ library. Look at the source/matrix_impl.cpp file. I have an extern "C"
block which contains the functions I need, ending with _
. I have compiled this code against lapack/blas as well as MKL with no issues. I have used gcc and intel compilers. It also compiles on my mac with framework Accelerate
.
Upvotes: 0