static и shared из одних исходников

Работаем на примере Qt 4.8.1. Почему нам надо 2 варианта сборки исходников debug shared и static release.

Потому что на debug shared мы развиваем (форкаем) и отлаживаем исходники Qt (процесс сборки здесь происходят намного быстрее), а на static release мы делаем боевую версию для распространения (освобождаемся от небходимости таскать с собой какие-то dll-ки, подписываем наш exe ЭЦП нашего CA (центра сертификации) и т.д..

Итак задача собирать static и shared из одних исходников, то есть буквально из одной папки src.

Возможно после конфигурирования с помощью config.exe , где мы указываем static или shared, мы получаем немного разные по содержанию pri и pro файлы ( не факт, надо проверить бы).

То есть файлы *.cpp и *.h не меняются, но pri/pro файлы не будут идентичными. И это есть проблема (на первый взгляд).

Но попытаемся еще раз пройти все цепочку настройки/сборки сначала.

При компиляции у нас четыре возможных ключа -MT -MTd -MD -MDd . MT MTd MD MDd ключи компиляции.

Эти ключи задаются глобально в файле qmake.conf для вашего тулчейна (у нас msvc-2010): Где настраиваются ключи компиляции и сборки.

У нас всего 4 варианта каталогов для разделения объектных файлов, moc файлов и т.д.

debug_shared
release_shared
debug_static
release_static

И получается, что тут наши варианты сборок не пересекаются.

Также у нас в каждом каталоге сборки  имеется:

Makefile
Makefile.Debug
Makefile.Release

которые к сожалению при выполнении qmake.exe для static и shared вариантов будут перезаписываться каждый раз заново. Но только если это не теневая сборка.

А при теневой сборке можно все варианты Makefile, Makefile.Debug, Makefile.Release индивидуально раскидать по разным каталогам сборки.

И еще у нас один каталог lib для собранных qt библиотек. И вот его нельзя изменить, так как путь к нему прописан внутри файла qmake.exe.

config.exe -debug -shared

Не теневая сборка ( т.е. tmp внутри каталогов исходников) проходит нормально.

Получили в tmp\obj\debug_shared объектные файлы. tmp\obj\debug_release остался пустым (как и ожидалось).

В этом случае объектные файлы собираются в каталогах tmp\obj\debug_shared.

В каталог lib попадает :
qtmaind.lib 97
QtCored4.lib 1713
QtCored4.dll 4796
QtXmld4.lib
QtXmld4.dll
QtTestd4.lib
QtTestd4.exp
QtSqld4.lib
QtTestd4.dll
QtSqld4.dll
QtNetworkd4.lib
QtNetworkd4.dll
QtGuid4.lib 4947
QtGuid4.dll 14217
....

И вот тут надо остановиться, так как судя по названиям созданных библиотек компиляция вся шла с ключом -MTd, хотя напрашивался -MDd. Но отладка работает нормально. Это получился так называемый static_debug вариант.

Но вот теневая сборка закончилась с ошибкой (ключ -MTd ). И это не правильно. Где поменять -MTd на -MTDd смотрите здесь : MT MTd MD MDd ключи компиляции.

Небольшое правило: для надежности везде где собирались tmp а также Makefile, Makefile.Debug, Makefile.Release удаляем их вручную (гарантированно).

Далее в qmake.conf прописываем нужный нам ключ MDd.

Пересобираем исходники Qt в теневую папку (получается на одном уровне с каталогом src). И сборка проходит успешно (с ключом MDd).

Теперь на тех же исходниках запустим сборку static release.

config.exe ... -static -release

Запускаем заново батник с вызовом config.exe, то есть делаем заново конфигурацию теперь уже с ключами -static -release.

Пробуем собрать src в теневой каталог.

config.exe .... -static -release ....

В каталогах теневой сборки release_static как и полагается появились объектные файлы. В остальных папках debug_static и т.д. как и полагается файлы не появились.

Статическая сборка в теневом каталоге завершилась УСПЕШНО!

В каталоге lib появились статические библиотеки и их наименование немного отличается от разделяемых из debug shared варианта, но важно, что это все-таки абсолютно разные файлы.

qtmain.lib внимание без буквы 4 и так далее для остальных !!
QtCore.lib - static
....
QtNetwork.lib - static
...

В режиме static release компиляция идет с ключом -MT (как и полагается):

cl -c -nologo -Zm200 -Zc:wchar_t- -O2 -MT -GR -EHsc -MP -GL -W3 -w34100 -w34189 -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT -DTARGET=BIT_driverKKT -DAppExeName=BIT_driverKKT -DTHIS_IS_QT_CREATOR -DQT_NO_DEBUG -DQT_SQL_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT -I"..\..\..\..\QtSDK1.2.1\QtSources\4.8.1\include\QtCore" -I"..\..\..\..\QtSDK1.2.1\QtSources\4.8.1\include\QtNetwork" -I"..\..\..\..\QtSDK1.2.1\QtSources\4.8.1\include\QtGui" -I"..\..\..\..\QtSDK1.2.1\QtSources\4.8.1\include\QtSql" -I"..\..\..\.

Тестируем варианты сборок исходников qt (библиотек) на тестовом проекте.

Запускаем тестовую программу, собираем как static release и она работает как надо (никаких) зависимостей от каких бы то ни было dll. Запускается и отдельно без Qt Creator.

Запускаем тестовую программу, собираем как debug shared и собирается и запускается из под Qt Creator нормально и запускается с отладкой.

Все пока хорошо. Но теперь о главном. Предположим мы форкаем исходники Qt (4.8.1) (например как у нас здесь Наконец-то наша версия QpSqlTabelModel ).

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

Если у нас используются теневые сборки (то есть static release и debug shared разнесены по индивидуальным каталогам), то проблем не возникнет оказывается.

Во в всяком случае мы можем проверить, изменить немного (допустим сделать qDebug() ), в каком-нибудь файле например QSqlTableModel.

А далее мы открываем Qt Creator и делаем Build (НЕ ReBuild) и видим, что только нужная нам библиотека пересобралась (и очень даже быстро), в нашем случае QtSql.lib.

И так делаем отдельно для static release и debug shared вариантов сборки.

Таким образом получается, что можно делать статику и динамику из одних исходников Qt.

А ещё лучше сделать bat файлы и переключаться с конфигурации dll shared на relase static : разделение lib для статики и динамики