Кросс компиляция linux windows

Кросс-компиляция и отладка C++ Windows-приложения под Linux

Показали мне недавно интересное приложение, под которое можно разрабатывать плагины. Приложение оказалось очень полезным для научной работы, но вот незадача — приложение разработано под Windows, у меня стоит Ubuntu. Windows для разработки под это приложение от лаборатории получить пока не удалось. Чтобы не тратить время, решил освоить кросс-компиляцию и отладку этого приложения.

Итого, имеется:
Ubuntu 12.10 x64
Не-юникодное приложение Мастерская Граф-Моделей (МГМ) (В командах консоли будет называться gmw.exe)

Нужно:
Разрабатывать и отлаживать плагины (dll-библиотеки), не устанавливая Windows.

И тут нам помогут Wine, Code::Blocks, портированное GDB, и boost.

Wine, не юникодное приложение, английский интерфейс Ubuntu и русский язык

При попытке открыть не юникодное приложение под Wine

получаются зюки следующего вида:

На эту проблему интернет очень быстро дает следующую подсказку:

В моём случае, данный подход не улучшил ситуацию ни на йоту.
Как выяснилось, русских локалей в системе не было добавлено (тыц).

Теперь запускаем с выше-указанной подсказкой

И, вуаля, запускается приложение с читаемым русским текстом:

Настройка IDE Code::Blocks для кросс-компиляции и отладки

Установка Code::Blocks

В дальнейшем для отладки нам потребуется менять код плагина отладки поэтому лучше сразу взять версию Code::Blocks из под svn.
Устанавливаем svn:

С помощью svn получаем код C::B, для этого переходим в папку, в которую хотим сохранить код C::B, где и набираем:

Переходим в полученную папку ‘trunk’.

Компиляция C::B происходит с помощью g++, autotools, automake и некоторых других утилит, которые необходимо установить:

Кроме того Code::Blocks зависит от wxWidgets:

Подстраиваем установщик под компьютер (можно запускать единожды):

И дальше, устанавливаем сам codeblocks (ключ —prefix можно упустить для использования настроек по-умолчанию):

Более подробно можно посмотреть по ссылке.

Настройка компиляции и линковки

Выполняем пункты с 1 по 5 с форума Code::Blocks. После этого компиляция программ должна работать, если не используется линковка к платформо-зависмым библиотекам (линковка с boost::regexp будет рассмотрена позже).
(*) В новом Code::Blocks немного изменилось меню по сравнению с инструкцией. Настройки искать нужно в ‘Settings->Compiler. ‘. Для старого Code::Blocks (10.05) пункт 5 нужно выполнить полностью, для нового же (12.11) настройку касающуюся gdb в 5 пункте пока трогать не будем.

Если используется boost его лучше положить отдельно от /usr/include, т.к. по этому адресу лежит много linux-специфичных заголовочных файлов, которые мы не хотим включать в проект при компиляции под Windows.

UPD: При настройке линковки в поле «Other Linker Options» имеет смысл добавить опцию «-Wl,—subsystem,windows,—kill-at», которая помечает, что это реально Windows DLL, и, что самое главное, запрещает использовать декорирование символов (—kill-at) при экспорте функций с соглашением вызова __stdcall. Подрбнее здесь и здесь.

Начиная с пункта 7 по ссылке выше, описывается кросс-отладка, но, к сожалению, insight.exe, упоминающийся в инструкциях, найти не удается. Поэтому пойдем своим путем.

Кросс-отладка в Code::Blocks & MingW32 gdb для Windows

gdb, который является родным для линукса частично умеет отлаживать Windows приложения, правда, умеет он только останавливаться на исключениях и почти всегда игнорирует точки останова. Чтобы справиться с этими проблемами скачиваем gdb в пакете mingw32 под Windows. Для этого скачиваем и затем распаковываем и переходим в подпапку ‘bin’. Устанавливаем gdb под Windows:

Читайте также:  Как происходит загрузка операционной системы linux

Теперь в этой же папке bin появился файл gdb.exe, он-то нам и нужен.

Создаем скрипт для имитации обычного gdb для этого в файл /usr/bin/i586-mingw32msvc-gdb

Заносим следующие строки:

Для старого C::B все уже настроенно, для нового же отладчик нужно настроить дополнительно. В пункте ‘Settings->Debugger’ кликаем по ‘GDB/CDB debugger’ затем по ‘Create Config’. В новом конфиге меняем команду запуска отладчика на ‘/usr/bin/i586-mingw32msvc-gdb’, остальные настройки по желанию. После этого идем в ‘Settings->Compiler. «, в пункте ‘Selected Compiler’ выбираем тот компилятор, который настраивали до этого и затем на вкладке ‘Toolchain executables’ меняем ‘Debugger’ на наш свежесозданный конфиг. Теперь отладчик будет останавливаться на точках останова, хотя и остановить программу в произволльный момент не сможет (данная проблема пока еще не решена). Правда при попытке отладить,C::B выдает следующую ошибку:

Эта ошибка говорит о том, что плагин отладчика в C::B не понимает выдачу отладчика gdb.exe. Как выяснилось при ближайшем рассмотрении плагин отладчика имеет платформо-зависимый код, и вот тут-то и нужно вспомнить что у нас есть исходники C::B. Мы сейчас слегка подкоррекируем код этого плагина. Нужно будет поменять код только одного файла ‘/src/plugins/debuggergdb/gdb_driver.cpp’
Для этого нужно перейти в корень проекта C::B (откуда запускалась команды ./bootstrap), по умолчанию это папка ‘trunk’. И накактить патч:

Ну и пересобираем Code::Blocks:

И почти все готово, остается только создать проект. Шаги 12-13 по ссылке. Если же вы хотите создать проект dll-библиотеки, то указывайти создание динамической библиотеки в мастере и переименовывайте разширение в dll.
Проверям, что в настройках проекта стоит выбранная нами цепь компилятор-линкер-отладчик. ‘<Правая клавиша на проект>-Build Options. ‘ пункт ‘Selected compiler’, и можно радоваться и отлаживаться. Напомню, что по какой-то причине отладчик не может быть прерван во время исполнения, т.е. все отладочные действия могут буть применены только во время останова программы. В частности нельзя поставить новую точку останова, если программа не стоит на какой-либо другой точке останова…

Линкование статической библиотеки boost’а

Библиотека boost в основном является набором заголовочных файлов, и потому никаких проблем с линковкой обычно не возникает. Но для некоторых частей boost’а необходимо линковаться к статической библиотеке, например, boost::regex. Пробуем собрать проект и получаем:

Ошибка возникает из-за того, что мы пытаемся прилинковаться к linux билиотеке, для того чтобы построить windows-приложение.
Чтобы слинковаться нужно скомпилировать boost::regex с помощью MingW32 (про кросс-компиляцию). Скачиваем boost, распаковываем и переходим в папку с распаковынным boost’ом. Создаем файл user-config.jam в корне домашней директории:

Со следующим содержанием:

Дальше настраиваем сборку и собираем:

После выполнения последней команды у меня были ошибки «failed updating 1 target», что, правда, не мешает собираться программам.

В результате, у нас есть полностью подготовленная среда для написания, сборки и отладки Windows-приложений или Windows-библиотек из под Linux. Теперь можно приступать к работе…

Источник

Кросс-компиляция в docker. Почему бы и нет?

Что такое кросс-компиляция? Какие есть инструменты для сборки бинарных файлов для Windows в Linux? Как настроить docker-контейнер для всего этого? Вот лишь небольшая часть вопросов, которые будут обсуждаться ниже.

Инструменты

Кросс-компиляция позволяет получить исполняемый код для платформы, отличной от той, на которой запускается этот процесс.

В рамках данной статьи рассмотрим кросс-компиляцию для платформы Windows в Linux.

Читайте также:  C windows system32 scrnsave scr

Примером кросс-компилятора может служить Mingw-w64. По сути он предоствляет лишь инструмент для сборки приложения, но, если Вам необходимы сторонние библиотеки, которые не являются частью STL, придется собирать их и зависимости. Так же можно использовать готовые бинарные файлы, так как это описано в этой статье.

Упростить настройку сборки позволяет проект mxe, который предоставляет не только инструменты, но и библиотеки. С их списком можно ознакомиться на официальном сайте. При установке библиотек используется контроль зависимостей, т.е. будет установлен требуемый пакет и все необходимое для его работы. Инструменты поставляются в пред-настроенной конфигурации, например, для статической сборки 64-битных приложений. Это существенно облегчает сборку.

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

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

Контейнеризируй это

Допустим, что сборка релиза для Windows у нас настроена на локальной машине. Релизы выходят довольно часто, в некоторых версиях добавляются новые библиотеки, а, некоторые, например, удаляются. В один прекрасный день начальник требует скинуть сборку релиза на новичка. Как ему настроить свою среду сборки? Какие библиотеки нужно взять из репозитория mxe, а для каких выполнить сборку из исходников?

На этот случай можно завести bash-скрипт, который будет разворачивать всю среду в заданной папке. И после пытаться поддерживать этот скрипт в актуальном состоянии. Но, как и документация к проекту, в один критически важный момент он может устареть.

Хорошим решением будет изолировать нашу среду для сборки внутри docker-контейнера. Сам docker-файл будет содержать самодостаточный набор инструкций по развертыванию среды, а наличие контейнера позволит избежать захламления домашней системы лишними библиотеками.

Собираем все вместе

Для демонстрации возьмем простой Qt-проект — SimpleQtProject. Этот проект собирается утилитой qmake, и состоит из одной единственной формы. Сделано это, конечно же, для простоты. Так же в папке docker лежит файл для сборки контейнера.

Рассмотрим docker-файл проекта. По сути он состоит из нескольких основных частей:

  • установка зависимостей для системы сборки
  • установка и настройка системы сборки
  • компиляция проекта и копирование артефактов на хост-систему

Ниже рассмотрены лишь основные команды из файла, для полного ознакомления рекомендуется обратиться к репозиторию.

Пропустим первый пункт и перейдем непосредственно к установке mxe.
Клонируем репозиторий:

На момент написания статьи последним релизом был build-2019-06-02. Здесь не используется ветка мастер по простой причине: необходима повторяемость сборки. В противном случае, при добавлении новых коммитов в мастер сборка может сломаться.

Далее настраиваем систему сборки:

Данная команда добавит инструменты (экземпляры cmake и Mingw-w64 и пр.) для статической сборки проекта под 64-битную архитектуру, а после соберет с их помощью Qt.

Следующим шагом добавим в PATH путь к исполняемым файлам mxe:

После того, как среда сборки настроена, можно перейти непосредственно к последнему пункту:

Здесь следует пояснить несколько моментов. Предполагается, что при запуске контейнера, в папку /app/src/ будет смонтирована папка с исходниками, содержащая *.pro файл, а в директории /app/res/ смонтировано место, куда следует сложить результаты сборки.

Ниже приведен пример команды для создания docker-image, ее необходимо запускать в папке docker рассматриваемого проекта:

Сборка же запускается там же:

Читайте также:  Hp 1536 драйвер для линукс

Перед выполнение команды необходимо создать папку result в директории docker для копирования результатов.

Кастомизация сборки

По умолчанию mxe предоставляет MinGW версии 5.5.0 (по крайней мере это справедливо для сборки build-2019-06-02).

Если в проекте используются новые фичи С++ 17, то такая версия компилятора неудовлетворительна. К счастью, среда сборки предоставляет более новые версии в виде отдельных плагинов. Для решения нашей задачи, необходимо в команду сборки библиотек добавить инструкцию по использованию соответствующего плагина:

Данная команда создаст комплект для статической сборки 64-битных приложений с использованием компилятора седьмой версии (7.4.0). Если такой комплект уже существует, то он изменен не будет.

Со списком всех доступных плагинов можно ознакомиться на странице.

В директории mxe/src содержатся *.mk файлы, которые описывают параметры сборки того или иного пакета. При необходимости можно внести требуемые коррективы в уже существующий пакет или добавить свой собственный. Структура файлов описана вот тут — https://github.com/mxe/mxe/wiki/Add-a-New-Package:-Full-Version.

Для копирования pзависимостей проект mxe предоставляет утилиту copydlldeps.sh. Но это не единственный полезный инструмент, с их олным списокм можно ознакомиться на странице.

CMake и статическая линковка Qt

Так сложилось, что в своем проекте я использовал Qt и систему сборки CMake. Когда было принято решение о сборке проекта для Windows, отличным решением выглядело собрать все используя статическую линковку, чтобы пользователям предоставлять один бинарь, без каких-либо зависимостей.

Разбирая целую гору ошибок линковщика, удалось выяснить, что такая сборка из коробки не работает, вообще нигде. Дело в том, что qmake при использовании статической линковки генерирует *.cpp-файл, в котором находятся инструкции по импортированию плагинов, примерно такого вида:

Так же добавляются флаги и библиотеки для этапа линковки в Makefile.

Можно попробовать поэкспериментировать вот с такой конструкцией в CMakeLists.txt:

А дальше добавить в target_link_libraries использование plugin_libs . Но для меня такой подход не принес никаких результатов.

В конце концов, я пришел к решению динамически линковать (по возможности) все внешние библиотеки и копировать вместе с исполняемым файлом еще и необходимые dll с помощью copydlldeps.sh. Более подробно про разворачивание под Qt под Windows описано в статье.

В заключении

Выше было показано, как за несколько простых шагов можно настроить среду для кросс-компиляции проекта. Но, к сожалению, в реальных условиях все не так радужно.

Хоть проект mxe предоставляет внушительный список библиотек, но все равно он может не включать тех, которые нужны именно Вам, или включать слишком новые версии. Да, есть возможность самому создать пакет или, на худой конец, собрать библиотеку из исходников. Но не все можно сбилдить кросс-компилятором, так мне не удалось сделать это с проектом cpprestsdk, потому что ему нужен установленный vcpkg.

Многие проблемы, которые могут появиться при сборке проекта кросс-компилятором, характерны для кросс-платформенной разработки вообще. Например, у меня была странная ошибка из-за элемента перечисления ERROR . Оказалось, что в одном из заголовочных файлов Windows имеется макрос с таким же именем. Его подстановка и ломала весь код.

Это дело каждого — использовать кросс-компиляцию или нет. Мне это принесло неплохой профит. Я настроил сборку под несколько дистрибутивов Linux и Windows в отдельных docker-контейнерах для своего проекта SecureDialogues, добавил один make-файл для запуска процесса поочередно для каждого контейнера. Далее запускаю make и через некоторое время получаю бинарные файлы для требуемых ОС в локальной папке.

Источник

Оцените статью