Qt. Статическая сборка проекта

28.10.2009
Новиков Максим Глебович

Содержание

Общие положения

Если вас не устраивает необходимость распространять вместе со своим приложением файлы использованных в нём библиотек, то можно статически включить нужные их функции в исполнимый файл. Для этого надо провести некоторые подготовительные действия, которые и будут описаны ниже.

Объединение библиотечных функций с исполнимым модулем имеет смысл лишь при небольших проектах, да и то ощутимого выигрыша в размере исполнимого файла вы не почувствуете. Всё-таки библиотека разрабатывалась, как системная, и поэтому используемые вами в проекте библиотечные функции завязаны с другими функциями библиотеки и тянут за собой практически весь код соответствующей dll-ки. Поэтому при статической сборке распространена практика последующего сжатия разбухшего исполнимого файла специальными программами, например UPX, позволяющими уменьшить его размер в 2-3 раза.

Кроме того, в проекте придётся обойтись без использования исключений, поскольку на настоящий момент так и не найдено способа включить их библиотеку mingwm10.dll в состав исполнимого модуля (за исключением изврата в виде программного выделения этого файла из ресурсов с сохранением его на диск с последующим запуском основного кода программы). Но в малых проектах исключения, как правило не используют, а отказ от их поддержки к тому же, уменьшит код программы практически на 30%.

Статическая сборка проекта подразумевает также обязательное статическое подключение используемых в нём плагинов (это тоже библиотечные файлы, но выполненные несколько обособленно). При статической сборке проекта плагины в виде отдельных dll работать с ним не будут.

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

  1. Проект, небольшой по размерам.
  2. Отказ от исключений.
  3. Статическое подключение всех используемых плагинов.
  4. Сжатие итогового файла компрессором исполнимых файлов.

Скажу несколько слов о длительности процессов по переориентации библиотеки на статический режим сборки, которые я буду описывать ниже. Нам потребуется перекомпиляция всей библиотеки Qt, что может занять до нескольких часов машинного времени. Все упомянутые в этой главе интервалы времени, занимаемые процессом настройки и компиляции библиотеки Qt, приведены мной для конфигурации Pentium 4 3,2 ГГц и Windows XP SP3, установленной на виртуальной машине VirtualBox запущенной в Linux, с выделенной ей памятью 1 Гб. Не самая шустрая конфигурация, поэтому в вашем случае всё может пройти значительно быстрее.

Для выполнения команд настройки и сборки нам придётся немного поработать в командной строке Windows. Это не настолько страшно, как кажется на первый взгляд. Консоль командной строки можно вызвать через «Пуск → Все программы → Стандартные → Командная строка». Но гораздо удобнее вызывать консоль из какого-нибудь файлового менеджера, например из Total Commander. Удобство заключается в том, что в вызываемой консоли уже установлен текущий путь открытой в менеджере папки, и нам не придётся после каждого вызова устанавливать его там консольными командами и ручным набором текста. Специализированные программы работы с консолью, такие как Windows PowerShell, Сonsole и даже платная PowerCmd менее удобны в этом плане. Кнопку вызова консоли в программе Total Commandr для удобства можно вытащить прямо на его панель инструментов, и присвоить ей значок из ресурсов консоли, указав для этого в окне выбора иконки на файл <WINDIR>\system32\cmd.exe.

[Вернуться в начало]

Выполнение переориентации библиотеки

Итак, как уже говорилось выше, для того, чтобы включить библиотеки Qt*.dll в файл программы, нам требуется особым образом перенастроить установленную библиотеку Qt программой configure.exe (находится в корне библиотеки) запустив её с ключём -static и затем пересобрать её программой mingw32-make.exe из пакета компилятора (аналога привычной утилиты make). Замечу, что программа make.exe из пакета MSYS, использованная для этой же цели, в конце сборки Qt выдаёт ошибку, поэтому ей в данном случае пользоваться не следует.

Чтобы убрать зависимость от библиотеки mingwm10.dll, следует отказаться от использования в коде исключений и во время конфигурирования библиотеки добавить к прочим ключам файла configure.exe ключ -no-exceptions. Иного способа избавления от этой библиотеки (например, путём включения её в состав исполнимого файла), пока не найдено.

В некоторых источниках предлагают отредактировать файл <QTDIR>\mkspecs\win32-g++\qmake.conf, изменив значения переменных QMAKE_LFLAGS или QMAKE_LFLAGS_DLL. Я провёл несколько экспериментов, и не заметил какого бы то ни было влияния этих переменных на результат сборки библиотеки или проекта.

Итак, перед началом компиляции сделаем копию папки библиотеки. Одна папка останется на случай необходимости динамической компиляции релиза (с dll-ками) и для собственно разработки и отладки программы, а другая будет использована только для статической компиляции проекта при создании релиза. Кстати, если по какой-то причине вы решили во время работы со статической библиотекой запустить Qt Designer, в его палитре вы не найдёте каких либо установленных вами дополнительных компонент (хотя на форме они будут видимы), пока не скопируете их dll-ки в папку <QTDIR>\plugins\designer из соответствующей папки динамического варианта библиотеки.

Теперь приступим к практическим действиям по переориентации библиотеки. Если вы уже компилировали Qt ранее, то перед началом процесса перекомпиляции необходимо удалить все объектные и другие промежуточные файлы предыдущей сборки, выполнив в корневой папке библиотеки Qt команду:

    mingw32-make.exe confclean

Такая очистка может занять около от 15 минут до часа. После окончания работы команды очистки в той же папке следует запустить команду конфигурирования:

    configure.exe -static -release -no-qt3support -no-exceptions

-static — нам нужна статическая сборка
-release — собираем только нужную нам часть библиотеки без отладочных её вариантов (Debug), экономя время компиляции и итоговый размер папки библиотеки.
-no-qt3support — не собираем устаревшие модули, включённые для совместимости со старыми проектами (экономим время компиляции и итоговый размер папки библиотеки).
-no-exceptions — не включаем функции работы с исключениями.

Порядок следования вышеуказанных ключей неважен. Информацию обо всех ключах утилиты configure.exe можно посмотреть здесь: http://www.qtinfo.ru/qt4configure или набрав

    configure.exe -help

После запуска команды на вопрос о выборе редакции Qt отвечаем «o» (Open Source Edition), для согласия с лицензией GPLv3 нажимаем «y» (yes). Конфигурирование библиотеки займёт также от 15 минут до часа. Далее запускаем компиляцию:

    mingw32-make.exe sub-src

sub-src — компилируем только исходники самой библиотеки (в том числе и исходники плагинов), но без проектов примеров, инструментов разработки типа Qt Designer и т.п.

Компиляция даже с нашими экономными настройками займёт от 2,5 до 4 часов. После её завершения получим 2 папки. Одна — для написания проекта в режиме Debug и выпуска динамически скомпанованных релизов в режиме Release, а другая — только для выпуска статически скомпанованных релизов, не использующих исключения, в режиме Release. Таким образом, перед окончательной компиляцией статического релиза следует просто переименовать папки (например, «4.6.0» переименовать в «4.6.0-no-static», а «4.6.0-static» в «4.6.0») и переключить в Netbeans режим с Debug на Release. К сожалению, в настройках Netbeans 6.8 пока ещё нет привязки режимов компиляции к разным папкам Qt, хотя слухи о введении такой настройки в этой версии программы были.

[Вернуться в начало]

Статическое подключение плагинов

Теперь займёмся статическим подключением плагинов — подключаемых модулей, выполняющих определённый набор функций. Если вы использовали в своей программе, например, изображение в формате jpg, то за его отображение отвечает плагин qjpeg. Плагины — это тоже библиотечные файлы dll-формата, зачастую сторонние, и для их статической компиляции требуется выполнить ещё несколько несложных действий. Плагины, которые возможно подключить статически, с расшифровкой выполняемых ими действий перечислены тут: http://doc.crossplatform.ru/qt/4.6.x/plugins-howto.html.

Итак, предположим, нам надо включить плагины qjpeg4.dll и qico4.dll в состав исполнимого модуля нашей программы, поскольку как отдельные плагины, они работать со статически скомпилированной программой уже не будут. Для этого нам надо совершить всего 2 действия:

  1. Задублируем файл настроек проекта qt-Release.pro, назвав его qt-Release_static.pro и добавим в него строку «QTPLUGIN += qjpg qico». Через Netbeans это делается так: откроем в свойства проекта, щёлкнув на его имени правой кнопкой мыши и выбрав соответствующий пункт. В левой части открывшегося окна переключимся на подкатегорию Build → Qt, а в самом верху правой части окна нажмём кнопку менеджера конфигураций. В открывшемся окне выберем конфигурацию Release и выполним её дублирование. Переименуем новую конфигурацию в Release_static и нажмём ОК чтобы вернуться в основное окно настроек. Теперь в поле выбора конфигурации (слева от нажимаемой нами только что кнопки менеджера конфигураций) переключим конфигурацию на вновь созданную, и ниже, в окне настроек, в разделе Expert найдём пункт Custom Definitions. Отредактируем его, вставив туда строку:

    QTPLUGIN += qjpg qico

    Закроем окно настроек, нажав Ок.
     
  2. Теперь откроем основной файл проекта с процедурой main, и сразу после директив #include впишем:

    #include <QtPlugin>
    Q_IMPORT_PLUGIN(qjpeg);
    Q_IMPORT_PLUGIN(qico);

На этом настройка закончена. В панели инструментов переключаемся на вновь созданную конфигурацию Release_static и компилируем проект. В итоге указанные библиотеки будут включены в состав исполнимого файла.

В принципе, всё должно заработать, но если какие-либо плагины при таком подключении начнут конфликтовать с кодом, можно попробовать ограничить их своим пространством имён:

    #include <QtPlugin>
    QT_BEGIN_NAMESPACE
Q_IMPORT_PLUGIN(qjpeg);
Q_IMPORT_PLUGIN(qico);
QT_END_NAMESPACE

В некоторых случаях для удачного компилирования требуется также добавить пути к библиотекам плагинов и файлы самих библиотек. Эту информацию прописывают в файле qt-Release.pro в параметре LIBS. Чтобы сделать это через Netbeans, откройте настройки проекта, переключитесь на подкатегорию Linker, и в настройке Runtime Search Directories выберите нужные папки, содержащие файлы библиотек, а в настройке Libraries — соответствующие статические библиотеки. Замечу, что статические библиотеки не имеют в своём названии цифры версии. Этим они отличаются от динамических («релизных» с цифрой версии и отладочных с буквой d перед цифрой версии).

[Вернуться в начало]
[Оставить отзыв в гостевой]
Hosted by uCoz