【问题标题】:Cross-compile Fortran library from Linux to Windows using CMake including Lapack使用包括 Lapack 在内的 CMake 将 Fortran 库从 Linux 交叉编译到 Windows
【发布时间】:2018-06-14 20:45:39
【问题描述】:

我有一个一直在 Linux 上开发的 Fortran 库,我想与通常使用 Windows 的同事分享。我不希望他们帮助开发它,所以我要做的就是使用交叉编译器生成一个静态可执行文件,以便他们可以运行它。

我可以使用 Linux (openSUSE) 上的交叉编译器工具链编译简单的 Hello world 程序,该程序在 Windows 上运行没有问题,但是当我尝试将可执行文件链接到另一个库 (Lapack) 时,Windows 抱怨它也找不到动态链接的.dll 文件。在我的问题中,我展示了如何使用

编译源代码

最小的工作示例

我使用 openSUSE,它提供了一个交叉编译组件的存储库。首先,我安装了 mingw64-cross-toolchain 以及相关的 lapack 和 blas 开发文件:

mingw64-cross-gcc
mingw64-cross-g++
mingw64-cross-gfortran
mingw64-lapack-devel
mingw64-blas-devel

这还带来了许多其他必需的软件包

我的最小工作树如下所示:

├── linalg_mod.f90
└── main.f90

linalg_mod.f90 本质上是一些 lapack 例程的薄包装,而 main.f90 是我的主程序。它们本身并不是很有趣,main 包含一个简单的 3x3 矩阵,需要求解然后输出解。

> cat main.f90
program main
  use iso_fortran_env, only: wp=>real64
  use linalg, only: linsolve_quick
  implicit none

  integer :: ii
  real(wp) :: A(3,3), b(3), x(3)

  A = reshape([1, 2, -3, -2, 1, 2, 3, 1, -2], shape=([3,3]))
  b = [7, 4, -10]

  call linsolve_quick(3, A, 3, b, x)
  do ii = 1,3
    print'(a1,i1,a3,f8.5)', 'x', ii, ' = ', x(ii)
  enddo

end program main

linalg 模块有点大,所以我把它复制到了一个 Github gist - 如果你有兴趣,可以阅读 here


在 Linux 上本地编译:

> gfortran -c linalg_mod.f90 main.f90
> gfortran linalg_mod.o main.o -o main -llapack -lblas
> ./main
  x1 =  2.00000000     
  x2 = -1.00000000     
  x3 =  1.00000000

据我了解,在 Linux for Windows 上进行交叉编译稍微有点棘手,因为您需要将库捆绑为静态可执行文件。我编译的 Linux 本机代码是动态的,如下所示:

> ldd main
    linux-vdso.so.1 (0x00007fffb65be000)
    liblapack.so.3 => /usr/lib64/liblapack.so.3 (0x00007f9346bdc000)
    libblas.so.3 => /usr/lib64/libblas.so.3 (0x00007f9346982000)
    libgfortran.so.4 => /home/user/Software/gcc/install/lib64/gcc/x86_64-pc-linux-gnu/7.0.1/libgfortran.so.4 (0x00007f93465ad000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f93462b0000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f9346098000)
    libquadmath.so.0 => /home/user/Software/gcc/install/lib64/gcc/x86_64-pc-linux-gnu/7.0.1/libquadmath.so.0 (0x00007f9345e59000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f9345ab6000)
    libgfortran.so.3 => /usr/lib64/libgfortran.so.3 (0x00007f934578c000)
    /lib64/ld-linux-x86-64.so.2 (0x0000558391f9e000)

添加-static 属性创建静态可执行文件:

> gfortran -c mod.f90 linalg_mod.f90 main.f90
> gfortran linalg_mod.o mod.o main.o -static -o main -llapack -lblas 
> ldd main
    not a dynamic executable

尽管 main 不是动态可执行文件,但我仍然不完全相信它与 lapack 和 blas 动态库完全隔离。有没有更好的检查方法?


从 Linux 到 Windows 的交叉编译

我正在尝试使用这些相同的步骤将上述代码交叉编译为 Windows 可执行文件。在linux上我做如下。 注意:lapack 和 blas 库可通过 mingw64 存储库作为静态和动态库使用(具体来说,包 mingw64-liblapack3mingw64-lapack-devel):

/usr/x86_64-w64-mingw32/sys-root/mingw/bin/liblapack.dll
/usr/x86_64-w64-mingw32/sys-root/mingw/lib/liblapack.dll.a
/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libblas.dll
/usr/x86_64-w64-mingw32/sys-root/mingw/lib/libblas.dll.a

我假设静态库是以.dll.a 结尾的文件,而动态库是以.dll 结尾的文件。类似于原生 Linux 上的编译步骤,这是我尝试创建静态 main.exe 文件的方法

> x86_64-w64-mingw32-gfortran -c mod.f90 linalg_mod.f90 main.f90
> x86_64-w64-mingw32-gfortran linalg_mod.o mod.o main.o -static -o main.exe -llapack -lblas 
> ldd main.exe
    not a dynamic executable

一切看起来都不错,除了当我将可执行文件移动到我的 Windows 机器时,尝试在 Git bash 中执行文件时出现以下错误:

> ./main.exe
K:/temp-dump/main.exe: error while loading shared libraries: liblapack.dll: cannot open shared object file: No such file or directory

看看它的动态库也很有趣:

> ./ldd.exe ./main.exe
ntdll.dll => /c/windows/SYSTEM32/ntdll.dll (0x7ffe37c20000)
KERNEL32.DLL => /c/windows/system32/KERNEL32.DLL (0x7ffe35ab0000)
KERNELBASE.dll => /c/windows/system32/KERNELBASE.dll (0x7ffe34da0000)
msvcrt.dll => /c/windows/system32/msvcrt.dll (0x7ffe37430000)
USER32.dll => /c/windows/system32/USER32.dll (0x7ffe37760000)
GDI32.dll => /c/windows/system32/GDI32.dll (0x7ffe35920000)

由于某种原因,在 Linux/Windows 之间没有维护 lapack 的静态链接。有没有办法强制将交叉编译的可执行文件从 Linux 静态链接到 Windows?

【问题讨论】:

    标签: linux windows cross-compiling lapack mingw-w64


    【解决方案1】:

    这花了很长时间,而且解决方案非常简单......

    显然,我需要做的就是将.dll 文件与可执行文件放在同一目录中。我刚刚将以下.dlls 复制到我的 Windows 机器上,现在它工作正常。这些是我需要复制的文件:

    /path/to/windows/drive/
    ├── libblas.dll
    ├── libgcc_s_seh-1.dll
    ├── libgfortran-4.dll
    ├── liblapack.dll
    ├── libquadmath-0.dll
    ├── libwinpthread-1.dll
    └── main.exe
    

    【讨论】:

    • 我已经使用相同的 x86_64-w64-mingw32 工具链编译了一个 Windows 应用程序,但是当我将我的应用程序移动到我的 Windows 计算机时,我遇到了一个错误,说我缺少 libgcc_s_seh-1.dll。我知道这个文件需要与我在 Windows 上的可执行文件一起打包,但是我从哪里得到它?在这种情况下,你是从哪里得到的?
    • 我在抱怨另一个丢失的 *.dll 时遇到了类似的错误。当我放置 -static 选项时它已修复。
    • @NathanF.:至少对于 Ubuntu,我在 gcc-mingw-w64-x86-64 package 中找到了它们。 cp /usr/lib/gcc/x86_64-w64-mingw32/*-win32/*.dll /path/to/build/files/ 成功了。
    猜你喜欢
    • 2021-05-03
    • 2017-06-22
    • 2021-03-04
    • 1970-01-01
    • 2023-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多