【发布时间】: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-liblapack3 和 mingw64-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