Кросс-компиляция библиотеки Fortran из Linux в Windows с использованием CMake, включая Lapack

У меня есть библиотека Fortran, которую я разрабатываю для Linux, и я хочу поделиться ею с коллегами, которые обычно используют Windows. Я не ожидаю, что они помогут в его разработке, поэтому все, что я хочу сделать, это создать статический исполняемый файл с помощью кросс-компилятора, чтобы они могли его запустить.

Я могу компилировать простые программы Hello world, используя набор инструментов кросс-компилятора в Linux (openSUSE), которые работают в 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 - вы можете прочитать это здесь если тебе интересно


Собственная компиляция в 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 для 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 не поддерживается. Есть ли способ заставить статическое связывание кросс-скомпилированного исполняемого файла из Linux в Windows?


person cbcoutinho    schedule 22.06.2017    source источник


Ответы (1)


Ну, это заняло целую вечность, и решение было поразительно простым ...

По-видимому, все, что мне нужно было сделать, это поместить файлы .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
person cbcoutinho    schedule 22.06.2017
comment
Я скомпилировал приложение Windows, используя ту же цепочку инструментов x86_64-w64-mingw32, однако, когда я перемещаю свое приложение на свой компьютер с Windows, я получаю сообщение об ошибке, в котором говорится, что мне не хватает libgcc_s_seh-1.dll. Я понимаю, что этот файл должен быть упакован вместе с моим исполняемым файлом в Windows, но откуда его взять? Откуда вы взяли это в данном случае? - person Nathan F.; 20.07.2020