Как правильно доставить программу, созданную с использованием MSYS2 и MingW, для конечных пользователей? - PullRequest
1 голос
/ 28 марта 2020

Я создаю C приложение на Windows, используя Msys2 и MingW.

Это приложение будет доставлено на настольные компьютеры Windows конечных пользователей, которые не разбираются в технологиях. У меня есть два вопроса по этому поводу:

  1. Каков наилучший практический способ доставки программы Windows, созданной с использованием Msys64 и MingW, на другую машину Windows, которая не имеет эти установлены? Некоторые источники в inte rnet и здесь в SO говорят, что у нас нет другого выбора, кроме как распространять файл exe в том же каталоге вместе с MingW dll s, от которого он зависит. Или, чтобы статически связать exe с MingW dll s. Но я хотел бы убедиться, что это действительно стандартные способы сделать это. Кажется странным, что у MingW не было бы лучшего способа.

  2. Предположим, что упомянутый exe также в какой-то момент использует LoadLibrary API для динамической загрузки dll (думаю, плагин) система). Это dll было также построено с использованием MingW (и в этом случае, конечно, оно будет отправлено конечным пользователям вместе с exe). Что-нибудь особенное, что мне нужно сделать, чтобы убедиться, что dll будет успешно загружен на пользовательский компьютер без установленного MingW?

  3. В дополнение к 2: нужна ли указанная DLL библиотека импорта (.lib), присутствующая во время компиляции на компьютере разработчика и / или во время запуска на конечном компьютере?

РЕДАКТИРОВАТЬ: Пожалуйста, позвольте мне уточнить, я не с использованием MSYS2 в качестве оболочки командной строки. Я работаю напрямую с Mingw gcc через Windows cmd и просто получил Mingw из каталога загрузки MSYS2.

Ответы [ 2 ]

2 голосов
/ 29 марта 2020

Я предполагаю, что этот вопрос касается MSYS2 и mingw-w64, так как не существует такого понятия, как «msys64».

MSYS2 предлагает три различных target системы:

  • Windows 32-бит
  • Windows 64-бит
  • MSYS2

, каждый из которых имеет совершенно отдельные исходные деревья для своих инструментов разработки и пакетов при установке MSYS2.

Это не следует путать с различными системами сборки - Сборка системы может быть либо Win32, либо Win64. Например, если вы выбрали Win64 в качестве системы сборки и выбрали установку всех трех целевых систем, у вас будут деревья msys64/mingw32, msys64/mingw64 и msys64/usr

Установщик MSYS2 создает сценарии запуска для каждого из них. цель, которую вы установили.


Если вы нацелены на Win32 или Win64, то скомпилированные двоичные файлы (exe или dll) можно распространять как отдельные продукты. Вы можете сделать сборку stati c с помощью g cc или clang, создав отдельный автономный исполняемый файл, или вы можете сделать сборку, которая зависит от DLL, которые вы распространяете вместе с исполняемым файлом.

Для бинарных дистрибутивов является стандартным включение всех файлов, которые им требуются и не предоставляются целевой операционной системой, это не является особенностью mingw-w64.

Поиск LoadLibrary путь описан в документации MSDN .

Если вы нацелены на MSYS2, то полученный двоичный файл ДОЛЖЕН быть запущен в оболочке MSYS2. Эта цель предлагает некоторые функции POSIX, которые не поддерживаются напрямую mingw-w64. Это можно считать вилкой Cygwin. Можно было бы распространять двоичный файл с таргетингом на MSYS2 вместе с кучей библиотек DLL, скопированных из установки MSYS2, которые вы определили с помощью средства отслеживания зависимостей.

2 голосов
/ 28 марта 2020

Я не вижу никаких недостатков в этом решении.
Я не большой пользователь Windows, но я должен признать, что решение неявного поиска динамических c библиотек, где стоит исполняемый файл, очень помогает.
Вы помещаете весь контент вашего приложения (исполняемые файлы и динамические c библиотеки / плагины) куда угодно, и как только вам удастся запустить исполняемый файл, все остальное будет найдено.

Конечно, если вы планируете поставлять много разных приложений с общим подмножеством динамических c библиотек, может быть лучше разместить все эти библиотеки в одном месте и соответствующим образом изменить переменную среды PATH.
Но это не стоит усилий для одного приложения.

В приложении на основе mingw-w64 (не совсем Msys64 и MingW, но очень близко) (с плагинами), которое я поставил несколько месяцев за go, я просто предоставил libgcc_s_seh-1 .dll, libstdc ++ - 6.dll и libwinpthread-1.dll в качестве дополнения к моим собственным двоичным файлам, и это работало без каких-либо пр oblem.
Использование objdump.exe -p my_program.exe (затем рекурсивно для отображаемого результата) помогает найти необходимые динамические библиотеки (например, ldd в Linux или otool -L в Macosx).

Это то, что мне нравится в mingw-подобном решении: оно создает собственное приложение Windows, которое не зависит от многих других необычных компонентов (которые пользователь должен был бы получить первым).


Нет необходимости иметь дело с некоторыми .lib файлами; достаточно создать .dll и связать его (см. пример ниже).
Он работает точно так же, как мы делаем на UNIX (с .so файлами).
Я действительно не знаю, почему Visual -C ++ использует очень сложную комбинацию файлов .lib и .dll ...


Я только что протестировал этот простой пример.

file prog.cpp

#include <windows.h>
#include <iostream>

__declspec(dllimport)
int
my_library_function(int arg);

int
main()
{
  std::cout << "~~~~ entering " << __func__ << " ~~~~\n";
  int result=my_library_function(123);
  std::cout << "result=" << result << '\n';
  std::cout << "~~~~ still in " << __func__ << " ~~~~\n";
  HINSTANCE lib=LoadLibrary("my_plugin.dll");
  if(lib)
  {
    FARPROC symbol=GetProcAddress(lib, "my_plugin_function");
    if(symbol)
    {
      int (*fnct)(int)=NULL;
      memcpy(&fnct, &symbol, sizeof(fnct));
      int result=fnct(123);
      std::cout << "result=" << result << '\n';
    }
    FreeLibrary(lib);
  }
  std::cout << "~~~~ leaving " << __func__ << " ~~~~\n";
  return 0;
}

файл my_library.cpp

#include <iostream>

__declspec(dllexport)
int
my_library_function(int arg)
{
  std::cout << "~~~~ entering " << __func__ << " ~~~~\n";
  std::cout << "arg=" << arg << '\n';
  std::cout << "~~~~ leaving " << __func__ << " ~~~~\n";
  return 2*arg;
}

файл my_plugin.cpp

#include <iostream>

extern "C" __declspec(dllexport)
int
my_plugin_function(int arg)
{
  std::cout << "~~~~ entering " << __func__ << " ~~~~\n";
  std::cout << "arg=" << arg << '\n';
  std::cout << "~~~~ leaving " << __func__ << " ~~~~\n";
  return 2*arg;
}

процесс сборки

==== compiling [opt=0] my_plugin.cpp ====
g++ -o my_plugin.o my_plugin.cpp -c   -g -O0  -MMD -pedantic -Wall -Wextra -Wconversion -Wno-unused -Wno-unused-parameter -Werror -Wfatal-errors -UNDEBUG  -std=c++17 -Wno-missing-braces -Wno-sign-conversion

==== linking [opt=0] my_plugin.dll ====
g++ -shared -o my_plugin.dll my_plugin.o   -g -O0

==== compiling [opt=0] my_library.cpp ====
g++ -o my_library.o my_library.cpp -c   -g -O0  -MMD -pedantic -Wall -Wextra -Wconversion -Wno-unused -Wno-unused-parameter -Werror -Wfatal-errors -UNDEBUG  -std=c++17 -Wno-missing-braces -Wno-sign-conversion

==== linking [opt=0] my_library.dll ====
g++ -shared -o my_library.dll my_library.o   -g -O0

==== compiling [opt=0] prog.cpp ====
g++ -o prog.o prog.cpp -c   -g -O0  -MMD -pedantic -Wall -Wextra -Wconversion -Wno-unused -Wno-unused-parameter -Werror -Wfatal-errors -UNDEBUG  -std=c++17 -Wno-missing-braces -Wno-sign-conversion

==== linking [opt=0] prog.exe ====
g++ -o prog.exe prog.o   -g -O0 -lmy_library

выполнение

C:\Work\PluginTest>prog.exe
~~~~ entering main ~~~~
~~~~ entering my_library_function ~~~~
arg=123
~~~~ leaving my_library_function ~~~~
result=246
~~~~ still in main ~~~~
~~~~ entering my_plugin_function ~~~~
arg=123
~~~~ leaving my_plugin_function ~~~~
result=246
~~~~ leaving main ~~~~

C:\Work\PluginTest>

Это все еще работает, когда каталог mingw64 (содержащий цепочку инструментов) переименовывается, как только файлы libgcc_s_seh-1.dll, libstdc++-6.dll и libwinpthread-1.dll помещаются в тот же каталог, что и prog.exe.
Он даже работает, когда prog.exe запускается нажатием (не из командной строки); чтобы увидеть это, мне пришлось добавить бесконечный цикл в конце программы, чтобы окно оставалось открытым достаточно долго, чтобы видеть отображаемые сообщения.

...