кросс компиляция на windows
Кросскомпиляция программ для Windows с использованием MinGW, Boost и Cmake в openSUSE
Давным-давно в далекой-далекой галактике один программист заметил, что проект скомпилированный в VisualStudio 2005 выполняется в Windows ощутимо медленнее, чем при использовании GCC в Linux. И решил программист сравнить производительности проекта при использовании VisualStudio и GCC под Windows.
Проект является приложением, написанным на языках С и С++ с использованием библиотек Boost и системы сборки CMake.
Ниже рассказывается о создании окружения для сборки проекта на базе кросскомпилятора MinGW-w64, библиотек Boost и Cmake в openSUSE 11.3 x86.
Установка MinGW и Boost
Установка не должна представлять особой сложности. MinGW-w64 есть в репозиториях openSUSE. Для компиляции приложений для Windows x86 нужно добавить в систему репозиторий http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_11.3/, а для Windows x86-64 — http://download.opensuse.org/repositories/windows:/mingw:/win64/openSUSE_11.3/.
Это связано с тем, что в BSD-сокетах дискриптор сокета знаковый тип, а в Windows — беззнаковый. Если не сделать данную замену, то приложения использующие Boost.Asio, которая в Windows ожидает беззнаковый тип SOCKET не будут компилироваться. К негативным последствиям можно отнести потенциальную возможность неправильной работы приложений, которые расчитаны на то, что тип дескриптора сокета может быть только знаковым.
На этом установка окружения завершена.
DLL файлы для распространения приложения находятся в каталоге /usr/i686-pc-mingw32/sys-root/mingw/bin ( /usr/x86_64-pc-mingw32/sys-root/mingw/bin в случае Windows x86-64). Для того, чтобы определить, какие DLL-библиотеки использует скомпилированное приложение можно воспользоваться программой Dependency Walker, которая успешно работает под wine-1.3.10.
Кросскомпиляция с использованием Cmake
Файл i686-pc-mingw32.cmake содержал следующие настрйки:
На этом установка завершена. Теперь можно компилировать Windows-приложения прямо из рабочего оружения на Linux.
QtCreator: Qt кросс-компиляция из linux 64 в linux 32, win32, win64 и Mac OS X; upx, usb, dmg, etc
Библиотека Qt позволяет делать действительно кроссплатформенные приложения. Единожды написанный код можно откомпилировать под многие операционные системы. Но проблема именно в слове «компилировать», т.к. подразумевается, что необходимо перезагрузиться под целевую систему, иметь в ней настроенную среду разработки, установленный и настроенный зоопарк библиотек. Спасает кросс-компиляция — компиляция, производящая исполняемый код для платформы, отличной от той, на которой исполняется.
Кросс-компиляция для Windows 64
Обычно одной из наиболее востребованных проблем является сборка Windows-версии своего приложения, изначально разрабатывающегося под Linux. Пример решения этой проблемы можно увидеть тут или на русском. Необходимо создать mkspecs-конфигурацию, положить файлы Qt в соответствующие директории и всё. Компилировать Qt в таком случае не обязательно, можно скачать бинарники с официального сайта.
У такого подхода есть несколько минусов: 1) QtCreator об установленной таким образом библиотеке ничего не знает; 2) Официальной сборки Qt для Windows x64 не существует. И если с первой проблемой ещё как-то можно бороться, то против второй поможет только компиляция…
Перед кросс-компиляцией не забудьте поставить непосредственно сам кросс-компилятор (ищется в пакетом менеджере по названию «mingw»). И скачать исходники qt-everywhere с официального сайта. В директории mkspecs распакованного архива копируем папку win32-g++ в win64-x-g++ и корректируем содержимое файла qmake.conf. У меня получилось следующее:
По сути в файле спецификации были заменены только пути.
Соответственно, для такой сборки должен быть установлен пакет g++-mingw-w64-x86-64, содержащий в себе x86_64-w64-mingw32-g++ (в убунту пакет надо ставить отдельно).
Далее make && sudo make install. На первом этапе компиляции используется родной системный компилятор, он собирает необходимые утилиты для linux, которые будут использоваться для сборки уже windows-бинарников.
После установки у меня в /usr/local/qt4win64/bin лежат PE32+ DLL и несколько ELF 64-bit LSB executable, в том числе: qmake, uic, moc, rcc. Вот они то и пригодятся для QtCreator!
После установки не удаляйте распакованную директорию — она используется.
Кросс-компиляция для Windows 32
Аналогична компиляции для Win64. За исключением того, что есть официальная сборка, и саму библиотеку компилировать не нужно! Достаточно собрать qmake, uic, moc, rcc.
Кросс-компиляция для Mac OS X
Кросс-компиляция для мака тоже очень похожа, за исключением того, что надо будет собрать и компилятор. Я собирал по этой инструкции. Это отняло полный день времени и кучу нервов. В процессе будет нужна рабочая Mac OS X (как минимум на виртуальной машине) с установленным XCode, чтобы взять оттуда необходимые файлы. При компилировании своих Qt-приложений запущенная Mac OS X не нужна.
Помните, в Mac OS X для линковки с библиотекой .a-файлы не нужны.
Настройка QtCreator
Сначала нужно добавить в список все установленные компиляторы. Инструменты — Параметры — Сборка и запуск — Инструментарии:
QtCreator обычно нормально определяет ABI, но лучше перепроверить. Так же можно заметить, что системный x64 GCC в linux умеет генерировать и 32-битные приложения. Однако это не отменяет того, что также необходимы 32-битные версии библиотек.
После компиляторов можно добавить профили Qt:
Вот при добавлении профиля и пригодятся собранные ранее qmake, uic, moc, rcc, ведь нужно выбрать директорию с qmake. Жёлтый значок с восклицательным знаком слева от профиля означает warning, но QtCreator может использовать такой профиль Qt. А вот если значок красный, то профиль нерабочий. Такое может случиться при неправильной структуре каталогов. Или если удалить директорию, в которой компилировали Qt.
Следующие настройки нужно делать в каждом создаваемом проекте.
Для добавления конкретного профиля Qt надо при активном проекте зайти на вкладку «Проекты» (Ctrl+5):
По умолчанию в списке «Изменить конфигурацию сборки» есть только системный профиль Qt. Зато в списке кнопки «Добавить» есть все профили Qt, добавленные в параметры сборки.
В основных настройках сборки необходимо проверить пару библиотека-компилятор. Чтоб и то и другое было от одной и той же операционной системы.
Этапы сборки «qmake» и «Сборка» QtCreator ставит по умолчанию. А вот особые этапы «upx» и «dmgbuild» я добавил вручную для своего проекта. Этап «upx» выполняется каждый раз при нажатии на кнопку «Собрать проект». Однако если исполняемый файл не был изменён, то upx вернёт ошибку, что файл им уже обработан. В случае ошибки следующий этап не вызывается, т.е. dmg-файл обновится только если upx отработал успешно.
Для работы этапа upx он должен быть установлен в системе. Однако даже работая в linux-окружении и поставленный из пакетного менеджера upx умеет ужимать приложения: linux32/64, win32, macos32/64. Далеко не для всех проектов upx-сжатие реально нужно, этап показан скорее для примера.
Для этапа «dmgbuild» я воспользовался скриптом make_dmg. Ему нужны права root, поэтому добавил скрипт в файл /etc/sudoers
Изменения в проектном файле и использование сторонних библиотек
В моём проекте используется libusb, а это далеко не часть Qt. Также необходимо было включить платформенно-зависимую реализацию HID. В проектный файл были добавлены строки:
В Mac OS X и Linux линкуемся с системной libusb, в Windows в зависимости от разрядности линкуемся с libusb-1.0-32.dll.a или libusb-1.0-64.dll.a. Помним, что .a-файл может быть переименован, но зависеть приложение всё-равно будет от libusb-1.0.dll. В Linux параметры для libusb берём через системную утилиту pkgconfig. Кроме libusb подключаем для каждой операционной системы необходимые системные библиотеки и иконки.
Удобно разнести итоговые файлы для разных операционных систем по директориям. Сделать это можно так:
Цель win64-x-g++ относится к win32, однако в проектном файле идёт последней и переписывает настройки.
Кросс-компиляция Qt5 под Linux для Win x32/x64/static/shared
Документирование получения системы кросс-компиляции под Linux для Windows x32/x64/static/shared и сборка последней на момент описания Qt 5.4.1 в лайт-версии (для указанных четырех целей). Для себя, глубоко-обожаемого, ну и для пользы обществу.
Многие разработчики приходят к выводу, что использование *nix (в частности Linux) более предпочтительно для разработки приложений, используя фрэймворк Qt. И тому есть причины. Qt изначально ориентирована на *nix инструментарий, типа autotool, make, perl… И второй момент, под никсами есть прекрасный инструмент — valgrind, под виндой порта пока его не видел. Ну и последняя причина: просто удобно иметь набор инструментария для создания приложений под различные целевые платформы — в одном месте.
0. Сценарий сборки
Все шаги делаем последовательно. Желательно не объединять все скрипты в последовательную сборку по причине необходимости промежуточного «человечного» контроля. Разные дистрибутивы Линуха, разные среды исполнения, наборы инструментариев… Простой алгоритм: сделал очередной шаг, убедился в отсутствии ошибок, пошел делать следующий. Итак, сам сценарий:
1. Предварительная подготовка
У вас установлен дистрибутив Линукса. Желательно все это делать на на продакшен-компе (не на живом Линуксе), а установленном в виртуальную машину. Я например, пользуюсь VMWare, но это дело вкуса. Выбор дистрибутива Линукса — так же дело вкуса. Лично я предпочитаю Gentoo Linux, собственно под ним всю эту кухню и настраиваю. Если есть сложности в настройке, у меня есть небольшая статейка по этому вопросу: «Установка и настройка Linux Gentoo под VMWare».
Итак, у вас есть настроенный Линукс и вы работаете не под рутом! Для дальнейшей работы вам нужно проверить присутствие следующих установленных пакетов, или доустановить:
2. Установка среды кросс-компиляции MXE
Предварительное замечание об MXE. Это отличнейшая система сборки тулчейнов для кросс-компиляции. Но есть одно «но». В данный момент не существует стабильной ветки. Авторы до поры до времени вели две ветки в своем git-репозитарии — стабильную и «разработческую». Сейчас ветки объединены. Разработка идет ну очень активно — изменения сбрасываются чуть ли не раз 1-3 дня. А это чревато тем, что «то работает сборка, то не работает». Некоторые важные для меня библиотеки, в частности клиентская часть PostgreSQL, собираются без ошибок, но в нерабочем состоянии. Потратил неделю не исследование явных косяков. Исправляем эти «недочеты». Итак:
Cygwin или MinGW? Собираем программы для Windows без Windows
Содержание статьи
В общем-то, даже в Microsoft уже признали проблему и сделали WSL (Windows Subsystem for Linux), чтобы запускать те приложения, у которых нативных версий под Windows нет. Однако если ты хочешь сделать свою программу доступной для широкой аудитории, то WSL вовсе не панацея, поскольку у среднего пользователя эта система вряд ли установлена и у нативных приложений возможностей для интеграции с Windows все равно больше.
Во многих случаях камень преткновения — не сам код программы, а система сборки. Если ты используешь кросс-платформенные библиотеки и не вызываешь специфичные функции POSIX, портирование может вообще не требоваться. Главное — собрать исполняемые файлы.
GNU и Windows
Для сборки программ с помощью GNU toolchain на Windows часто используют два проекта: Cygwin и MinGW + MSYS. У них схожие цели, но разные детали реализации. Давай разбираться.
Cygwin
Cygwin — самая полная реализация окружения GNU для Windows. Он предоставляет большую часть POSIX API в виде библиотеки, что позволяет собирать программы из UNIX без портирования, если только им не требуется семантика UNIX. Яркий пример — демоны, им нужен fork() и сигналы, которых нет в Windows, да и службы Windows устроены совсем иначе.
Кроме библиотеки, дистрибутив содержит набор классических команд UNIX и терминал. Реализации команд используют эту библиотеку и поддерживают некоторые возможности UNIX, такие как регистрозависимые имена файлов.
Целевой способ использования: если нет желания или возможности портировать программу на Windows или использовать только платформенно независимые API, ее можно собрать «под Cygwin», ценой зависимости от cygwin1.dll и относительной изоляции от всей остальной системы.
MinGW и MSYS
Если цель Cygwin — сделать возможной сборку немодифицированных приложений на Windows ценой внешней зависимости, то цель MinGW + MSYS — производить приложения без внешних зависимостей.
MinGW и MSYS — это независимые пакеты, но их часто путают и смешивают друг с другом (а часто путают и с Cygwin). Можно сказать, что MinGW — это эквивалент GCC и binutils, а MSYS — расширенный эквивалент coreutils.
Начнем с MSYS. MSYS — это более «нативная» и легковесная альтернатива Cygwin. Этот пакет включает библиотеку с реализациями функций POSIX, но она предназначена для внутреннего пользования, и авторы категорически не рекомендуют связывать с ней свои приложения.
Библиотека MSYS не реализует UNIX поверх Windows, а следует соглашениям Windows — к примеру, сознательно не учитывает регистр букв в путях к файлам. Главная цель MSYS — предоставить нужные для скриптов сборки программы вроде Bourne shell, make и прочее, что обычно требуется для autotools.
MinGW содержит версии GCC и binutils (ассемблер as, компоновщик ld и так далее), которые производят исполняемые файлы для Windows в формате PE/COFF. Здесь мы и подходим к ключевому моменту: MinGW, как и все остальные части GNU toolchain, такой же платформенно независимый проект.
Кросс-компиляция в GNU toolchain уже давно обычное дело, и в GCC целевая платформа и хост независимы друг от друга. Можно запускать GCC на Linux для x86 и собирать программы для Linux на ARM, или наоборот. Совпадать не обязаны не только рабочая и целевая архитектуры процессора. Точно так же не обязаны совпадать даже ОС и формат исполняемого файла.
Ставим MinGW
Авторы многих дистрибутивов GNU/Linux уже постарались за нас, так что многие кросс-версии GCC, включая MinGW, можно поставить из репозиториев.
MinGW-w64, несмотря на название, поддерживает и Win32, и Win64. Это форк MinGW, который создали в первую очередь для реализации недостающей в оригинальном проекте поддержки Win64, отсюда и название.
Hello World
Тестирование кросс-компилированных программ для других архитектур — непростая задача, но, поскольку наша целевая платформа — Windows на x86, мы легко можем протестировать их в Wine:
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Кросскомпиляция выполняемых файлов Rust для Windows из Linux
Наверное не будет уж очень удивительным если я тут, на IT площадке Хабра, скажу что я иногда балую себя программированием.
я получил только сообщения об ошибках линкера:
Если кому интересно как я это поборол и теперь спокойно могу кросскомпилировать программы на Rust для Windows, не покидая Linux, добро пожаловать под кат.
Далее я рассматриваю только цели 32bit и 64bit pc-windows-gnu, цели pc-windows-msvc для меня интереса не представляют и поэтому в них я не углублялся. Так же речь будет идти о том дистрибутиве Linux, который установлен на моём компьютере, то есть Fedora Linux 31, но я не думаю что на других дистрибутивах Linux будут очень уж существенные различия. И я использую Rust установленный при помощи The Rust toolchain installer, а не входящий в репозиторий Fedora Rust по причине того, что мне иногда требуются nightly сборки Rust, которых в стандартном репозитории, естественно, нет.
Первым делом убеждаемся что у нас установлены необходимые цели, запустив следующую команду:
Получаем список всех возможных целей, и целей, которые у нас установлены:
или другой пакетный менеджер для нашего дистрибутива Linux:
При отсутствии MinGW устанавливаем необходимые пакеты, запустив
Ну вот вроде бы теперь всё в наличии, далее будем решать проблемы по мере их появления (ага, можно сказать что это получается прям какой-то Test-Driven Development, 🙂
Создаём простейший проект на языке Rust:
Сначала компилируем и запускаем его как родное приложение Linux:
Всё работает. Теперь пробуем его собрать как цель x86_64-pc-windows-gnu :
и получаем всё то же сообщение об ошибке сборки:
Пробуем собрать проект снова:
и получаем другую ошибку от линкера, уже от x86_64-w64-mingw32-gcc :
и опять запускаем компиляцию:
Опять ошибка линковки! Но уже другая:
Линкер жалуется на отсутствующие символы __onexitbegin и __onexitend в файле
и опять запускаем компиляцию нашего проекта на Rust:
Прекрасно! Всё собралось! Т.к. у меня установлен wine, то тут же я могу и проверить как это работает:
И даже работает! Теперь пробуем сделать то же самое для 32bit версии исполняемого файла Windows, делаем сразу run без предварительного build :
Ошибку с отсутствием символов __onexitbegin и __onexitend теперь уже в файле
/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnu/lib/crt2.o мы уже проходили, лечится точно так же, как и для 64bit цели заменой файлов crt2.o и dllcrt2.o на аналогичные по именам, но из дистрибутива MinGW из Fedora:
Тут теперь тоже всё собирается и работает.
И всё было прекрасно пока я не использовал никакие функции, которые паникуют (macro panic!, функция expect и т.д.) в 32bit целях для Windows. В целях 64bit всё хорошо, а вот в целях 32bit нет.
Добавим в наш проект панику:
и попробуем собрать как исполняемый файл для 64bit Windows:
И компилируется, и собирается, и работает. Попробуем теперь сделать то же самое, но в качестве цели укажем 32bit Windows.
Опять линкер жалуется на отсутствие символов, но теперь это символы _Unwind_RaiseException и _Unwind_Resume в модуле libpanic стандартной библиотеки Rust.
Снова раздумия, снова гугление, снова чтение доков и изучение исходников как самого Rust, так и его стандартной библиотеки. И я понял почему возникает такая ошибка.
Для разматывания стека при исключении Rust использует метод Dwarf для 32bit целей Windows и SEH для 64bit целей Windows, а MinGW из стандартного репозитория Fedora Linux использует метод SJLJ для 32bit целей Windows и SEH для 64bit целей Windows (о различии между этими методами читать тут). Поэтому 64bit цели собираются без вопросов, а для 32bit просто нет необходимых символов и объектных файлов. Чтобы получить данные файлы необходимо пересобрать MinGW с поддержкой Dwarf вместо поддерки SJLJ по умолчанию для 32bit целей Windows.