我有一个我在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是我的主程序。它们本身并不是很有趣,主要包含一个简单的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的主旨 - 如果你有兴趣可以阅读here
> 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 Linux上的交叉编译有点棘手,因为您需要将库捆绑为静态可执行文件。我编译的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动态库。有没有更好的检查方法?
我正在尝试使用这些相同的步骤将上述代码交叉编译为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?
答案 0 :(得分:2)
嗯,这需要永远,解决方案很容易让人感到轻松......
显然,我需要做的就是将.dll
文件和可执行文件放在同一目录中。我刚刚将以下.dll
复制到我的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