среда, 22 сентября 2010 г.

Сборка Qt без зависимостей (MS Visual Studio)

link
Часто, при попытке запуска Qt-зависимого приложения на "чистой" системе невозможна из-за отсутствия на ней redistributive paket MS Visual Studio ***. Это тем более становиться неожиданным, когда сам проект компилировался в операционной системе с заведомо установленной студией и никаких проблем не вызывал.

Простое решение - поставить статическую сбоку библиотек в настройке проекта - помогает только для MFC/ATL (не CLR) проектов. Но не для Qt! А всё потому, что изначально, библиотеки Qt:Framework Only для работы в MS Visual Studio содержат зависимости от msvc*.dll.

Задача: убрать зависимость Qt библиотек и приложений, их использующих, от динамических библиотек MS Visual Studio (msvc*.dll).


Все действия проводим до конфигурирования командой configure!

qmake.conf

Для начала изменим файл qmake.conf. Откройте его по адресу \mkspecs\win32-X\qmake.conf, где 'X' это версия Visual Studio:

msvc Visual Studio 6
msvc.net Visual Studio.NET 2002-2003
msvc2005 Visual Studio.NET 2005
msvc2008 Visual Studio.NET 2008

Потребуется внести следующие изменения:

Заменить

QMAKE_CFLAGS_RELEASE = -O2 -MD
QMAKE_CFLAGS_DEBUG = -Zi -MDd

На

QMAKE_CFLAGS_RELEASE = -O2 -MT
QMAKE_CFLAGS_DEBUG = -Zi -MTd

Этими ключами мы даем понять компилятору, что при сборке Qt необходимо статически прилинковать все необходимые библиотеки компилятора.

Но при попытке откомпилировать Qt, мы получим ошибку от mt.exe. Читаем дальше.

Manifest

Manifest - это файл, в котором, грубо говоря, описываются все зависимости приложения. При использовании статической компиляции библиотек компилятора, Manifest становится ненужным и не генерируется. И при попытке mt.exe присоединить его к проекту и получается ошибка. Чтобы избавится от этой проблемы, необходимо слегка изменить некоторые файлы.

Способ №1

В уже открытом нами файле qmake.conf:

Заменить

CONFIG += qt warn_on release incremental flat link_prl precompile_header autogen_precompile_source copy_dir_files
debug_and_release debug_and_release_target embed_manifest_dll embed_manifest_exe

На

CONFIG += qt warn_on release incremental flat link_prl precompile_header autogen_precompile_source copy_dir_files
debug_and_release debug_and_release_target

Т.е. удалить embed_manifest_dll embed_manifest_exe

Данными изменениями мы в явном виде запрещаем подключения манифестов к проекту.

Способ №2

Зайдем в директорию \mkspecs\features\win32\, и откроем файл embed_manifest_exe.prf с помощью любого текстового редактора.

Заменить

QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest \"$$replace(OBJECTS_DIR,/,\\)\\$${NOPATH_TARGET}.intermediate.manifest\"
-outputresource:$(DESTDIR_TARGET);1$$escape_expand(\n\t))

На

QMAKE_POST_LINK = $$quote(@if exist \"$$replace(OBJECTS_DIR,/,\\)\\$${NOPATH_TARGET}.intermediate.manifest\" mt.exe -nologo
-manifest \"$$replace(OBJECTS_DIR,/,\\)\\$${NOPATH_TARGET}.intermediate.manifest\" -outputresource:$(DESTDIR_TARGET);
1$$escape_expand(\n\t))

Тоже самое проделываем для файла embed_manifest_dll.prf

В измененной строке nmake проверит, сгенерирован ли манифест, и только в этом случае добавит его к проекту. Способ является более универсальным, хотя в большинстве случаев принципиальной разницы между ними нет.

Итог

Теперь осталось только запустить configure.exe с необходимыми вам ключами (включая -static), а затем использовать nmake. Все проекты, создаваемые при помощи qmake, уже будут иметь необходимые настройки.

Проверить проделанную работу можно, используя Total Commander. Достаточно только выделить любое приложение, откомпилированое с данной версией Qt, нажать F3 и во вкладке Dll Dependency убедится в отсутствии в списке MSVCR**.dll.

Опыт применения

Проделанные действия для Qt libraries 4.6.3 for Windows (VS 2008, 194 MB) в приложении к MS Visual Studio 2005 не привели к желаемому результату. Зависимость от MSVCR90.dll, которая наблюдается в Qt4.6.3 изменилась на зависимость от MSVCR80.dll. И, что бы в этом убедится, достаточно запустить компиляцию и дождаться появления (обновления) moc.exe в папке BIN. И F3 в Total Commander сразу подскажет стоит ли продолжать компиляцию.

Тем не менее, следующие действия решили проблему:

1. Выполнить замену ключей компилятора MD на MT и MDd на MTd, как описано выше.

2. Дописать в строке для линковщика QMAKE_LFLAGS = /NOLOGO /DELAYLOAD:\"OleAcc.dll\". Честно говоря, необходимость в этом действии сомнительна. Однако, строка параметров линковщика для проекта, созданного в MS Visual Studio 2005, для Shared... и Static... отличаются именно на /DELAYLOAD:\"OleAcc.dll\"

3. К параметрам configure.exe необходимо добавить ключ -no-crt. Без него линковщик спотыкается на MT (MTd) и выдаёт невообразимые ошибки. Это вызвано тем, что, вероятно, где-то в ключах компилятора прячется -clr, который и не даёт сделать статическую сборку.

Примечание. Применение ключа -static не обязательно для данной задачи. Манифесты так же трогать не обязательно.

Для удобства можно применить *.bat файл, следующего содержания:

::все переменные создадутся локально и будут безболезненно убраны
setlocal
::если у вас когда-то был QNX IDE это поможет
set MAKEFLAGS=
::переменные окружения от студии
call "C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat" x86
::путь куда установилась библиотека
set QTDIR=c:\Qt\4.6.3
set PATH=c:\Qt\4.6.3\bin;%PATH%
::собственно, для чего компилируется
set QMAKESPEC=win32-msvc2005
::перейти в папку с библиотекой
cd %QTDIR%
::на всякий случай %)
nmake confclean
::для ускорения процесса применены -fast -no-qmake
::(повторно компилировать qmake.exe нет необходимости).
configure -debug-and-release -opensource -fast -no-qmake -no-crt
::И без -static всё успешно компирирует
::А вот и причина приводящая к появлению большого количества свободного времени :)
nmake
::Это на случай запуска не из консоли.
pause
::Все переменные окружения безопасно изымаются.
endlocal


Если применялся -static, то в свойствах нового проекта: "Configuration Properties" -> "C/C++" -> "Code Generation" -> параметр "Runtime Library" должен быть выставлен на "Multi-threaded (/MT)".