Сборка в Ubuntu приложений для Windows
Представим себе ситуацию. Вы дома работаете только в Ubuntu и не
используете Windows, разработку приложений осуществляете с помощью
Qt Creator и библиотеки Qt. Требуется собрать приложение для
Windows (чтобы использовать его, например, на работе). Qt Creator
кроссплатформенная среда разработки и позволяет выполнить
эту задачу, т.е. собрать приложение для Windows в Ubuntu. Для этого
необходимо один раз настроить свою среду для выполнения такой задачи,
а затем пользоваться.
Сначала необходимо установить компилятор MinGW. Для этого запускаем
Центр приложений Ubuntu, набираем в строке
поиска mingw32, в найденном выделяем строку
Minimalist GNU win32 (cross) compiler и
нажимаем кнопку Установить. В результате будут установлены 3 пакета
mingw32_4.2.1.dfsg-2ubuntu1_i386.deb
mingw32-binutils_2.20-0.2_i386.deb
mingw32-runtime_3.15.2-0ubuntu1_all.deb
(версии файлов на момент написания статьи),
а непосредственно сам компилятор появится в папках
/usr/i586-mingw32msvc и /usr/amd64-mingw32msvc,
мы будем ориентироваться на первую.
Замечание. Если требуется установить компилятор на компьютер, на
котором нет доступа в интернет, можно воспользоваться способом, изложенным в соответствующей
статье.
Следующим шагом надо раздобыть необходимые файлы библиотеки Qt
для платформы Windows. Проще всего их взять на другом компьютере
с этой платформой. Пусть библиотека Qt установлена в папку C:\Qt\qt-4.8.2,
тогда выполняем следующие действия
1. Создаем в какой-либо временной папке, например,
D:\TEMP, папку qt4-win,
в которой будем собирать нужные файлы.
2. Копируем содержимое папок C:\Qt\qt-4.8.2\include
и C:\Qt\qt-4.8.2\lib соответственно в папки
D:\TEMP\qt4-win\include и D:\TEMP\qt4-win\lib.
3. Заголовочные файлы из папки C:\Qt\qt-4.8.2\include
ссылаются на файлы из папки C:\Qt\qt-4.8.2\src,
ее содержимое нам тоже надо получить. Если у Вас достаточно места,
лучше просто скопировать эту папку целиком (она весит больше 200
MB) в папку D:\TEMP\qt4-win\src. Однако,
есть у меня подозрение, что из этой папки могут потребоваться только
заголовочные файлы, по крайней мере, мне ни разу не встретилась
ситуация, когда бы это было не так. Поэтому, если есть желание сэкономить
место на диске, скопируем только заголовочные файлы. Для этого заблаговременно
создаем папку D:\TEMP\qt4-win\src, запускаем
командную строку и выполняем команду
xcopy C:\Qt\qt-4.8.2\src\*.h D:\TEMP\qt4-win\src /S
В результате будут скопированы только заголовочные
файлы с сохранением всех относительных путей, а размер папки D:\TEMP\qt4-win\src
составит меньше 40 MB.
4. Переносим папку D:\TEMP\qt4-win
на свой компьютер в Ubuntu, располагаем ее содержимое, например,
в /usr/qt4-win. Поскольку файлов очень много,
переносить их лучше в архиве.
5. После копирования (или распаковки) папки
/usr/qt4-win проверяем наличие доступа к
ее содержимому.
Замечание. Запись в папку /usr
возможна только с правами ROOT. В графическом интерфейсе получить
их можно, если нажать <AltF2>
и в открывшемся окне ввести команду gksu nautilus.
В результате после ввода пароля откроется файловый менеджер с правами
ROOT. Для установки доступа к содержимому папки /usr/qt4-win
можно кликнуть правой кнопкой мыши по ее значку в окне файлового
менеджера, открытого с правами ROOT, выбрать пункт контекстного
меню Свойства и на вкладке Права
установить следующее
В заключение следует нажать кнопку Распространить
права на вложенные файлы.
Если Вы планируете использовать в своих приложениях библиотеку
Qwt, необходимо иметь также файлы этой библиотеки, собранные для
платформы Windows. Берем их опять же на другом компьютере с платформой
Windows. Пусть библиотека Qwt установлена в папку C:\Qt\qwt-5.2.2,
выполняем действия, аналогичные тем, что описаны выше.
1. Создаем папку D:\TEMP\qwt5-win,
в которой будем собирать нужные файлы.
2. Копируем содержимое папок C:\Qt\qwt-5.2.2\include
и C:\Qt\qwt-5.2.2\lib соответственно в папки
D:\TEMP\qwt5-win\include и D:\TEMP\qwt5-win\lib.
3. Переносим папку D:\TEMP\qwt5-win
на свой компьютер в Ubuntu, располагаем ее содержимое в /usr/qwt5-win.
4. После копирования папки /usr/qwt5-win
проверяем наличие доступа к ее содержимому.
Далее необходимо создать новую спецификацию сборки, для этого в
каталоге /usr/share/qt4/mkspecs создаем
папку win32-x-g++, копируем в нее содержимое
папки win32-g++ из того же каталога и правим
файл qmake.conf из новой папки так, как
показано ниже в подсвеченных строках.
исходный файл qmake.conf
|
файл qmake.conf с
исправлениями
|
# |
# |
# qmake configuration for win32-g++ |
# qmake configuration for win32-x-g++ |
#
# Written for MinGW
#
MAKEFILE_GENERATOR = MINGW
TEMPLATE = app
CONFIG += qt warn_on release link_prl copy_dir_files debug_and_release
debug_and_release_target precompile_header
QT += core gui
DEFINES += UNICODE QT_LARGEFILE_SUPPORT
QMAKE_COMPILER_DEFINES += __GNUC__ WIN32
QMAKE_EXT_OBJ = .o
QMAKE_EXT_RES = _res.o
|
#
# Written for MinGW
#
MAKEFILE_GENERATOR = MINGW
TEMPLATE = app
CONFIG += qt warn_on release link_prl copy_dir_files debug_and_release
debug_and_release_target precompile_header
QT += core gui
DEFINES += UNICODE QT_LARGEFILE_SUPPORT
QMAKE_COMPILER_DEFINES += __GNUC__ WIN32
QMAKE_EXT_OBJ = .o
QMAKE_EXT_RES = _res.o
|
QMAKE_CC = gcc |
QMAKE_CC = i586-mingw32msvc-gcc |
QMAKE_LEX = flex
QMAKE_LEXFLAGS =
QMAKE_YACC = byacc
QMAKE_YACCFLAGS = -d
QMAKE_CFLAGS =
QMAKE_CFLAGS_DEPS = -M
QMAKE_CFLAGS_WARN_ON = -Wall
QMAKE_CFLAGS_WARN_OFF = -w
QMAKE_CFLAGS_RELEASE = -O2
QMAKE_CFLAGS_DEBUG = -g
QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses
|
QMAKE_LEX = flex
QMAKE_LEXFLAGS =
QMAKE_YACC = byacc
QMAKE_YACCFLAGS = -d
QMAKE_CFLAGS =
QMAKE_CFLAGS_DEPS = -M
QMAKE_CFLAGS_WARN_ON = -Wall
QMAKE_CFLAGS_WARN_OFF = -w
QMAKE_CFLAGS_RELEASE = -O2
QMAKE_CFLAGS_DEBUG = -g
QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses
|
QMAKE_CXX = g++ |
QMAKE_CXX = i586-mingw32msvc-g++ |
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS
QMAKE_CXXFLAGS_DEPS = $$QMAKE_CFLAGS_DEPS
QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON
QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF
QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE
QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG
QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC
QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD
QMAKE_CXXFLAGS_RTTI_ON = -frtti
QMAKE_CXXFLAGS_RTTI_OFF = -fno-rtti
QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions -mthreads
QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -fno-exceptions
QMAKE_INCDIR = |
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS
QMAKE_CXXFLAGS_DEPS = $$QMAKE_CFLAGS_DEPS
QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON
QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF
QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE
QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG
QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC
QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD
QMAKE_CXXFLAGS_RTTI_ON = -frtti
QMAKE_CXXFLAGS_RTTI_OFF = -fno-rtti
QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions -mthreads
QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -fno-exceptions
QMAKE_INCDIR = |
QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] |
QMAKE_INCDIR_QT = /usr/qt4-win/include |
QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS] |
QMAKE_LIBDIR_QT = /usr/qt4-win/lib |
QMAKE_RUN_CC = $(CC) -c $(CFLAGS) $(INCPATH) -o $obj $src
QMAKE_RUN_CC_IMP = $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
QMAKE_RUN_CXX = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $obj $src
QMAKE_RUN_CXX_IMP = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
|
QMAKE_RUN_CC = $(CC) -c $(CFLAGS) $(INCPATH) -o $obj $src
QMAKE_RUN_CC_IMP = $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
QMAKE_RUN_CXX = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $obj $src
QMAKE_RUN_CXX_IMP = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
|
QMAKE_LINK = g++ |
QMAKE_LINK = i586-mingw32msvc-g++ |
QMAKE_LINK_C = gcc |
QMAKE_LINK_C = i586-mingw32msvc-gcc |
QMAKE_LFLAGS =
QMAKE_LFLAGS_EXCEPTIONS_ON = -mthreads
QMAKE_LFLAGS_EXCEPTIONS_OFF =
QMAKE_LFLAGS_RELEASE = -Wl,-s
QMAKE_LFLAGS_DEBUG =
QMAKE_LFLAGS_CONSOLE = -Wl,-subsystem,console
QMAKE_LFLAGS_WINDOWS = -Wl,-subsystem,windows
QMAKE_LFLAGS_DLL = -shared
QMAKE_LINK_OBJECT_MAX = 10
QMAKE_LINK_OBJECT_SCRIPT= object_script
QMAKE_PREFIX_STATICLIB = lib
QMAKE_EXTENSION_STATICLIB = a
QMAKE_LIBS =
QMAKE_LIBS_CORE = -lole32 -luuid -lws2_32 -ladvapi32 -lshell32
-luser32 -lkernel32
QMAKE_LIBS_GUI = -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lwinmm
-lwinspool -lws2_32 -lole32 -luuid -luser32 -ladvapi32
QMAKE_LIBS_NETWORK = -lws2_32
QMAKE_LIBS_OPENGL = -lglu32 -lopengl32 -lgdi32 -luser32
QMAKE_LIBS_COMPAT = -ladvapi32 -lshell32 -lcomdlg32 -luser32
-lgdi32 -lws2_32
QMAKE_LIBS_QT_ENTRY = -lmingw32 -lqtmain
!isEmpty(QMAKE_SH) {
MINGW_IN_SHELL = 1
QMAKE_DIR_SEP = /
QMAKE_QMAKE ~= s,\\\\,/,
QMAKE_COPY = cp
QMAKE_STREAM_EDITOR = sed
QMAKE_COPY_DIR = cp -r
QMAKE_MOVE = mv
QMAKE_DEL_FILE = rm
QMAKE_MKDIR = mkdir -p
QMAKE_DEL_DIR = rmdir
QMAKE_CHK_DIR_EXISTS = test -d
} else {
QMAKE_COPY = copy /y
QMAKE_COPY_DIR = xcopy /s /q /y /i
QMAKE_MOVE = move
QMAKE_DEL_FILE = del
QMAKE_MKDIR = mkdir
QMAKE_DEL_DIR = rmdir
QMAKE_CHK_DIR_EXISTS = if not exist
}
|
QMAKE_LFLAGS =
QMAKE_LFLAGS_EXCEPTIONS_ON = -mthreads
QMAKE_LFLAGS_EXCEPTIONS_OFF =
QMAKE_LFLAGS_RELEASE = -Wl,-s
QMAKE_LFLAGS_DEBUG =
QMAKE_LFLAGS_CONSOLE = -Wl,-subsystem,console
QMAKE_LFLAGS_WINDOWS = -Wl,-subsystem,windows
QMAKE_LFLAGS_DLL = -shared
QMAKE_LINK_OBJECT_MAX = 10
QMAKE_LINK_OBJECT_SCRIPT= object_script
QMAKE_PREFIX_STATICLIB = lib
QMAKE_EXTENSION_STATICLIB = a
QMAKE_LIBS =
QMAKE_LIBS_CORE = -lole32 -luuid -lws2_32 -ladvapi32 -lshell32
-luser32 -lkernel32
QMAKE_LIBS_GUI = -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lwinmm
-lwinspool -lws2_32 -lole32 -luuid -luser32 -ladvapi32
QMAKE_LIBS_NETWORK = -lws2_32
QMAKE_LIBS_OPENGL = -lglu32 -lopengl32 -lgdi32 -luser32
QMAKE_LIBS_COMPAT = -ladvapi32 -lshell32 -lcomdlg32 -luser32
-lgdi32 -lws2_32
QMAKE_LIBS_QT_ENTRY = -lmingw32 -lqtmain
!isEmpty(QMAKE_SH) {
MINGW_IN_SHELL = 1
QMAKE_DIR_SEP = /
QMAKE_QMAKE ~= s,\\\\,/,
QMAKE_COPY = cp
QMAKE_STREAM_EDITOR = sed
QMAKE_COPY_DIR = cp -r
QMAKE_MOVE = mv
QMAKE_DEL_FILE = rm
QMAKE_MKDIR = mkdir -p
QMAKE_DEL_DIR = rmdir
QMAKE_CHK_DIR_EXISTS = test -d
} else {
QMAKE_COPY = copy /y
QMAKE_COPY_DIR = xcopy /s /q /y /i
QMAKE_MOVE = move
QMAKE_DEL_FILE = del
QMAKE_MKDIR = mkdir
QMAKE_DEL_DIR = rmdir
QMAKE_CHK_DIR_EXISTS = if not exist
}
|
QMAKE_MOC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc.exe |
QMAKE_MOC = /usr/share/qt4/bin/moc |
QMAKE_UIC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic.exe |
QMAKE_UIC = /usr/share/qt4/bin/uic |
QMAKE_IDC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc.exe |
QMAKE_IDC = /usr/share/qt4/bin/idc |
QMAKE_IDL = midl
QMAKE_LIB = ar -ru |
QMAKE_IDL = midl
QMAKE_LIB = ar -ru |
QMAKE_RC = windres |
QMAKE_RC = i586-mingw32msvc-windres |
QMAKE_ZIP = zip -r -9
|
QMAKE_ZIP = zip -r -9
|
QMAKE_STRIP = strip |
QMAKE_STRIP = i586-mingw32msvc-strip |
QMAKE_STRIPFLAGS_LIB += --strip-unneeded
load(qt_config) |
QMAKE_STRIPFLAGS_LIB += --strip-unneeded
load(qt_config) |
В заключение проверяем наличие доступа к содержимому
папки /usr/share/qt4/mkspecs/win32-x-g++.
Теперь все готово к сборке Ваших проектов для Windows. Сборка осуществляется
из командной строки терминала. Для сборки в конфигурации Выпуск
необходимо перейти в каталог с Вашим проектом и выполнить команды
qmake -r -spec win32-x-g++
make
В результате должен появиться исполняемый файл с
расширением exe. Для сборки в конфигурации
Отладка команды имеют вид
qmake -r -spec win32-x-g++ CONFIG+=debug
make
Несколько замечаний.
1) Для однозначности в команде qmake
можно указать файл своего проекта.
2) В Windows для версий библиотеки Qt младше,
чем 4.8.2, по умолчанию выбирается конфигурация сборки Отладка.
Конфигурацию сборки Выпуск необходимо в
команде qmake указывать явно параметром
CONFIG+=release. В Ubuntu, как видим, все
наоборот. Для версии Qt 4.8.2 в Windows выбирается конфигурация
сборки Выпуск (также как в Ubuntu), подробнее
об этом читайте здесь.
3) В Windows сборка проекта осуществляется в
папки debug или release
в зависимости от выбора конфигурации. В Ubuntu само по себе это
не происходит, обе конфигурации собираются в одну и ту же папку.
Если мы хотим добиться такого же порядка сборки как и в Windows,
в файл проекта необходимо включить строки
CONFIG(debug,debug|release)
{
MOC_DIR = debug
RCC_DIR = debug
OBJECTS_DIR = debug
DESTDIR = debug
} else {
MOC_DIR = release
RCC_DIR = release
OBJECTS_DIR = release
DESTDIR = release
}
4) Собирать приложение в Ubuntu для Windows
в конфигурации Отладка большого смысла
нет. Если отказаться от такой возможности, то можно уменьшить размер
папок /usr/qt4-win и /usr/qwt5-win,
удалив из них некоторые файлы библиотек, используемых только в конфигурации
Отладка. Например, в папке /usr/qt4-win/lib
имеются файлы
libQtGui4.a
libQtGuid4.a
Второй файл используется только в конфигурации
Отладка, поэтому его можно удалить. И далее
по аналогии... После такой очистки размер папки/usr/qt4-win
уменьшается со 104 до 64 MB, а размер папки /usr/qwt5-win
с 24 до 2,5 MB.
Остается перенести сформированный exe-файл на компьютер с платформой
Windows, но для его работы нужны dll-библиотеки Qt. Их можно взять
на компьютере с установленной библиотекой Qt, они лежат в папке
C:\Qt\qt-4.8.2\bin. Для большинства случаев
достаточно только двух файлов QtCore4.dll
и QtGui4.dll. Кроме того, не забываем про
dll-файлы библиотеки Qwt, если она используется в собранном приложении.
Общий объем библиотек можно сократить, если брать только релизные
версии файлов. Разместив dll-библиотеки в какой-либо папке, например,
C:\Qt-dll, прописываем в системе путь к
ней. Для этого кликаем правой кнопкой мыши по значку Мой
компьютер, выбираем пункт контекстного меню Свойства,
открываем вкладку Дополнительно, нажимаем
кнопку Переменные среды, выбираем переменную
Path, нажимаем кнопку Изменить
и дописываем через точку с запятой путь
C:\Qt-dll
Теперь все приложения, использующие библиотеку Qt,
будут работать на этом компьютере.
При подготовке статьи использовался ресурс Qt
& Ubuntu. Настраиваем среду для компиляции win32-приложений
|