码迷,mamicode.com
首页 > 其他好文 > 详细

Visual Stdio 环境下使用 GSL (GNU Scientific Library)

时间:2015-08-15 21:33:46      阅读:249      评论:0      收藏:0      [点我收藏+]

标签:

Visual Stdio 环境下使用 GSL (GNU Scientific Library)

GNU Scientific Library (GSL)是一个开源的科学计算的函数库,功能非常强大。网上介绍它的文章很多,而且 GSL 的文档也写的非常的好,属于那种特别容易上手的函数库。这里就不多对 GSL 进行介绍了。

今天要讲的是如何在 Visual stdio 环境下使用这个库。其实这方面的内容网上也有一些。不过采用的方法大多不太好。有的是直接下载 GSL for Widows 来使用,但是这个 GSL for Widows 是 2006 年的GSL 1.8 ,古董级的版本了,这个版本缺少的功能太多。

另一种方法是改造 MinGW 编译的生成的 dll。其实不同的 C 语言编译器编译生成的 dll 只要遵守相同的 C calling Conven,原则上是可以通用的。但是不同的编译器自带的库函数是有差别的。比如说 GSL 库中代码经常会用到 hypot 函数,这个函数在 MinGW 工具链中属于标准数学库中的函数。可以直接使用,但是 Visual stdio 的数学库中却没有这个函数。因此,直接拿来用 MinGW 的 gsl 是不行的,会在 link 阶段遇到缺少各种函数的定义的问题。

因此,如果想要在 Visual Stdio 环境下使用 GSL 最好的办法是重新编译 GSL 代码。简单说这又分成了两个不同的道路。

  • 使用 Visual Stdio 中的 C 编译器编译 GSL
  • 使用 MinGW 中的 C 编译器编译 GSL

其中第一种方法相对来说麻烦些。需要建立个 Visual Stdio 工程,将相关的代码添加到工程中,还需要修改个别几处 gsl 的代码(主要是因为 Visual Stdio 的 C 编译器不支持 C99 标准中的 inline 特性,GSL 代码中有几处不够严谨没有考虑这个问题)。 另外就是 Visual Stdio 的编译器生成 DLL 需要通过 def 文件来指定导出函数,这个 def 文件需要我们自己来生成,gsl 的源代码中没有给出。由于这种方法比较繁琐,对新手来说失败的可能性很大,因此我今天主要介绍另一种方法。

使用 MinGW 中的 C 编译器编译 GSL

熟悉 Linux 下软件编译的同学肯定都知道这种源代码编译安装都是标准的三个步骤:

  • ./configure
  • make
  • make install

我们编译 GSL 自然也摆脱不了这个工序。

当然在这之前我们需要有 MinGW 工具链和 MSYS 环境。在这里我建议大家使用 MSYS2,关于 MSYS2 的安装,可以参考我写的一篇短文:
http://blog.csdn.net/liyuanbhu/article/details/39397931

在工具链准备齐全之后,将 gsl-1.16.tar.gz 解压缩到 MSYS2 的home 目录中,之后就是 ./configure 。这个过程会比较长,可能要用 3、5分钟。

之后在 gsl-1.16 的根目录下就会有 config.h 文件了。对这个文件我们还需要改造一番。之所以要改造是因为这个文件是为 MinGW gcc 工具链准备的,对 Visual Stdio 开发工具来说不是那么适合。

下面就详细的说说这个 config.h 文件的内容。

config.h 的开头 25 行是这样的。

/* config.h.  Generated from config.h.in by configure.  */
/* config.h.in.  Generated from configure.ac by autoheader.  */

/* Disable deprecated functions and enums while building */
#define GSL_DISABLE_DEPRECATED 1

/* Define if you have inline with C99 behavior */
#define HAVE_C99_INLINE 1

/* Define to 1 if you have the declaration of `acosh‘, and to 0 if you don‘t.
   */
#define HAVE_DECL_ACOSH 1

/* Define to 1 if you have the declaration of `asinh‘, and to 0 if you don‘t.
   */
#define HAVE_DECL_ASINH 1

/* Define to 1 if you have the declaration of `atanh‘, and to 0 if you don‘t.
   */
#define HAVE_DECL_ATANH 1

/* Define to 1 if you have the declaration of `expm1‘, and to 0 if you don‘t.
   */
#define HAVE_DECL_EXPM1 1

#define HAVE_C99_INLINE 1 表明编译器支持 C99,虽然 VS 编译器不支持 C99 ,但是这句我们仍然可以保留。 因为 GSL 实际上只是使用到了 C99 的 inline ,其他的特性都没用到。 而 VS 编译器实际上也是支持 inline 的。关于这个 inline 的支持,我们后面还会详细的说。

acosh、asinh、atanh、expm1 这四个函数 VS 的标准库中都是不支持的。所以要将这四个 1 都修改成 0。 喜欢刨根问底的同学可能会问,VS 中缺少这些函数,会不会影响到 gsl 的功能呢。答案当然是否定的。这些不属于 C 语言标准的函数 GSL 都自己实现了一遍,有些放到了 sys 子目录中,有些放到了 utils 目录中,还有些分散到其他目录。

但是 GSL 实现都在函数名前加了 gsl 前缀。比如 expm1 函数,在 gsl 中实现为:

double gsl_expm1 (const double x)

如果 config.h 中配置为:

#define HAVE_DECL_EXPM1 0

则在 gsl 中所有用的 expm1 函数的地方都会调用 gsl_expm1 函数。

其他需要更改的地方还包括:

#define HAVE_DECL_FINITE 0
#define HAVE_DECL_FREXP 0
#define HAVE_DECL_HYPOT 0
#define HAVE_DECL_ISFINITE 0
#define HAVE_DECL_ISINF 0
#define HAVE_DECL_ISNAN 0
#define HAVE_DECL_LDEXP 0
#define HAVE_DECL_LOG1P 0
#define HAVE_IEEEFP_H 0
#define HAVE_IEEE_DENORMALS 0
#define HAVE_STRDUP 0
#define HAVE_STRINGS_H 0
#define HAVE_UNISTD_H 0

其中 hypot 函数实际上是有的,但是按照 微软的说法:

This POSIX function is deprecated beginning in Visual C++ 2005.

所以我们还是应该不用它。

有了 config.h 文件后我们就可以进行下一步了。

  • make

之后是漫长的等待。编译完成之后我们需要的文件就都有了。

gsl-1.16\cblas.libs 目录中可以找到如下文件:

  • libgslcblas.a
  • libgslcblas.dll.a
  • libgslcblas-0.dll

gsl-1.16.libs 目录中可以找到如下文件:

  • libgsl.a
  • libgsl.dll.a
  • libgsl-0.dll

将这些文件都拷贝出来, .a 文件改名为 .lib。

头文件在 gsl-1.16\gsl 目录中,可以将这个目录完整拷贝出来。

我们可以建立一个目录,名为 gsl-1.16-vs。
然后建立三个子目录,分别是 :

  • include
  • lib
  • bin

将头文件所在的 gsl 目录拷贝的 include 目录中, .lib 文件拷贝到 lib 目录中,.dll 文件拷贝到 bin 目录中。

至此,我们的工作就完成了大半了。大家可以试试我们生成的 lib 文件和 dll 文件,具体如何在 VS 中使用第三方的库,网上介绍文章有很多,我就不多说了。

gsl 帮助文件中的第一个例子:

#include <stdio.h>
#include <gsl/gsl_sf_bessel.h>
int main(int argc, char *argv[])
{
    double x = 5.0;
    double y = gsl_sf_bessel_J0 (x);
    printf ("J0(%g) = %.18e\n", x, y);
    return 0;
}

这个例子现在可以编译通过并顺利的执行了,得到的结果也是正确的。

但是这时我们还不能高兴太早。 Visual Stdio 还给我们预备了一个大坑等着我们往里跳呢。这个大坑就是 VS 编译器不支持 C99,当然也包括不支持 C99 的 inline。
所以在编译下面的代码时就会报许多错误。

#define HAVE_INLINE 1
#include "stdafx.h"
#include <stdio.h>
#include <gsl/gsl_vector.h>

    int _tmain(int argc, _TCHAR* argv[])
    {
        int i;
        gsl_vector * v = gsl_vector_alloc (10);
        for (i = 0; i < 10; i++)
        {
            gsl_vector_set (v, i, 1.23 + i);
        }
        for (i = 0; i < 10; i++) 
        {
            printf ("v_%d = %g\n", i, gsl_vector_get (v, i));
        }
        gsl_vector_free (v);
        getchar();
        return 0;
    }

报的错误主要是:

error C2054: 在“inline”之后应输入“(”

解决这个问题就要修改 gsl_inline.h 这个文件。这个文件有如下几行。

#ifdef HAVE_INLINE
#  if defined(__GNUC_STDC_INLINE__) || defined(GSL_C99_INLINE) || defined(HAVE_C99_INLINE)
#    define INLINE_DECL inline  /* use C99 inline */
#    define INLINE_FUN inline
#  else
#    define INLINE_DECL         /* use GNU extern inline */
#    define INLINE_FUN extern inline
#  endif
#else
#  define INLINE_DECL /* */
#endif

将其修改为 :

#ifdef HAVE_INLINE
#  if defined(__GNUC_STDC_INLINE__) || defined(GSL_C99_INLINE) || defined(HAVE_C99_INLINE)
#    define INLINE_DECL inline /* use C99 inline */
#    define INLINE_FUN inline
#  else
#    define INLINE_DECL         /* use GNU extern inline */
#    define INLINE_FUN __inline
#  endif
#else
#  define INLINE_DECL /* */
#endif

这样再编译就没有错误了。

我将编译好gsl放到了下面的链接里,有需要可以直接下载。
http://download.csdn.net/detail/liyuanbhu/9009755

版权声明:本文为博主原创文章,未经博主允许不得转载。

Visual Stdio 环境下使用 GSL (GNU Scientific Library)

标签:

原文地址:http://blog.csdn.net/liyuanbhu/article/details/47685377

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!