Возможно ли генерировать небольшие исполняемые файлы с помощью MINGW g ?

#linker #g #compilation

#компоновщик #g #Сборник

Вопрос:

Я понимаю, что MINGW-g компилирует большие исполняемые файлы, потому что он статически связывает многие вещи. С другой стороны, MSVC динамически связывается с библиотеками DLL из пакета VCRedist, и именно поэтому он создает исполняемые файлы намного меньшего размера.

Однако возможно ли аналогичным образом скомпилировать с g в Windows? Не обязательно MINGW-g , но что-то, что я могу использовать с Qt Creator (я не добавил Qt в качестве тега, потому что это не имеет отношения к вопросу).

Ответ №1:

MinGW прекрасно способен динамически подключаться к среде выполнения msvcrt. Единственная проблема, от которой вы не избавляетесь таким образом, — это код запуска GCC / MinGW, который не очень большой.

Небольшая тестовая программа на C (простая программа iostream hello world, примечание: я получил те же результаты для простой версии C printf).

 #include <iostream>

using namespace std;

int main()
{
cout << "Hello World!" << endl;
return 0;
}
  

Командные строки:

 g   main.cpp -MD -Os -s -o test.exe
cl /MD /Os main.cpp /link /out:test2.exe
  

Размеры исполняемых файлов:

GCC: 13 КБ

MSVC: 6 КБ

Хотя это двойное значение, весь необходимый код запуска объясняет большую разницу; для более крупных программ разница незначительна.

Комментарии:

1. Является ли переключатель -MD тем, который позволяет ему связываться со средой выполнения VC?

2. MinGW всегда ссылается на среду выполнения VC (the msvcrt.dll в C:WindowsSystem32 ). -MD просто делает то же самое, что и /MD для MSVC. Я думаю, вы неправильно понимаете, что такое / делает MinGW: он создает собственные исполняемые файлы точно так же, как компиляторы Visual Studio, но с помощью набора инструментов GNU. Таким образом, существует небольшой фрагмент кода, не разделяемый между ними, но все это всегда скрыто от пользователя. Также C ABI немного отличается (и g ссылается на libstdc от GCC, а не на MS, в отличие от библиотеки C, которая одинакова в обоих случаях), но это примерно суммирует разницу.

3. Вы пробовали удалять двоичные файлы?

4. Да, я это сделал. Кроме того, UPX (который тоже отключается). Моя проблема была конкретно с приложениями Qt, которые, как я видел, некоторые из предварительно скомпилированных примеров имели размер около ~ 100 КБ, но когда я их перекомпилировал, они были в 5-8 раз больше, а не с отладочной сборкой. К счастью, я только что узнал, что использование компилятора MS с Qt — это всего лишь вопрос использования Qt SDK версии MSVC.

5. @Tamas: что вполне возможно в вашем случае, так это то, что вы используете версию MinGW только со статической сборкой стандартной библиотеки C , что может объяснить дополнительное раздувание. Мой использует libstdc как dll. Но на самом деле, использовать MSVC с Qt совсем не сложно.

Ответ №2:

Чтобы провести справедливое сравнение между VC и MinGW с использованием статической компоновки, я бы предложил удалить переключатель компилятора / MD в синтаксисе командной строки выше. Это приведет к тому, что компилятор Visual C вместо этого будет статически связываться со статическими библиотеками, но все равно компилятор Visual C сгенерирует исполняемый файл гораздо меньшего размера, чем тот, который скомпилирован статически с помощью MinGW.

Поскольку компоновщик, используемый компилятором Visual C , имеет функцию, называемую связыванием на уровне функций, с помощью этого компоновщика связываются только необходимые библиотеки на основе функций, используемых в вашем коде. Любые не имеющие ссылок или неиспользуемые функции не будут связаны с конечным сгенерированным исполняемым файлом, что приведет к гораздо меньшему статически связанному двоичному файлу.

Возвращаясь к приведенному выше примеру с использованием компилятора Visual C , и на этот раз, используя статическое связывание, синтаксис командной строки будет следующим:

cl / Os main.cpp /ссылка /out:test2.exe

Здесь вы можете заметить, что я убрал переключатель /MD, чтобы компилятор использовал статическое связывание вместо динамического.

Теперь, чтобы создать гораздо меньший статически связанный исполняемый файл, я предлагаю синтаксис командной строки:

cl /Ox main.cpp /link /FILEALIGN:512 /OPT: REF /OPT: ICF /ИНКРЕМЕНТНЫЙ: НЕТ /out:test2.exe

Если вы проверите полученный двоичный файл, вы заметите, что он намного меньше, что опять же является статически связанным исполняемым файлом.

На самом деле я почерпнул эту идею из обсуждения на этом веб-сайте по адресу http://www.catch22.net/tuts/minexe

Большинство компиляторов Pascal, включая Delphi, также имеют ту же функцию компоновки, и она известна как интеллектуальная компоновка, но результирующие статически связанные исполняемые файлы намного меньше тех, которые создаются компилятором Visual C .

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

Я бы посоветовал удалить MinGW и вместо этого использовать компилятор Visual C . Даже разработчик MinGW, похоже, не заботится о сокращении объема кода с помощью статического связывания.

Комментарии:

1. Есть ли в MinGW встроенная замена компоновщику? Я бы хотел остаться с g , потому что большинство приложений, которые я разрабатываю, предназначены для кросс-компиляции в Linux и Windows. Если я использую g на обеих платформах, это относительно безболезненно.

2. В настоящее время я пытаюсь выполнить поиск в Google для замены, но прямо сейчас я еще не нашел подходящего ответа. Поскольку вы действительно хотите остаться с g без какого-либо раздувания кода, я советую вам использовать динамическую компоновку для этого компилятора и включить необходимые библиотеки DLL в ваше приложение, если вы хотите развернуть его на других машинах, чтобы избежать проблем с зависимостями, также известных как DLL-ад в среде Windows.

3. Если вы будете разрабатывать свое приложение в Linux, прилагаемый к нему компилятор gcc и g по умолчанию использует динамическое связывание, и, насколько я знаю, в большинстве дистрибутивов Linux есть все необходимые библиотеки времени выполнения для разрабатываемых вами приложений, поэтому, возможно, не нужно беспокоиться о том, какие библиотеки времени выполнения необходимо включить в ваше приложение, если вы хотите развернуть его на других машинах, использующих Linux.

4. Да, настройка по умолчанию в Qt Creator также динамически связывает сам Qt с приложением. Рекомендуемый метод развертывания — отправить библиотеки DLL в каталог приложения. Это работает, и все в порядке. Что меня не совсем устраивает, так это то, что основной размер exe-файла в gcc больше по сравнению с VC (хотя оба они динамически ссылаются на Qt).

5. Насколько велика разница в размере между тем, который скомпилирован с помощью VC , по сравнению с тем, который с MinGW использует динамическую сборку? Если он маленький, то нет необходимости утруждать себя этим.

Ответ №3:

Вы можете использовать cygwin (www.cygwin.com ). Они используют DLL времени выполнения, очень похожую на MSVCRT . Тогда ваша программа, конечно, зависит от среды выполнения cygwin (извините, это тавтология).