- The Rust Programming Language
- Установка
- Нотация командной строки
- Установка rustup на Linux или macOS
- Установка rustup на Windows
- Обновление и удаление
- Устранение возможных ошибок
- Локальная документация
- Кросскомпиляция выполняемых файлов Rust для Windows из Linux
- Cross-compile a Rust application from Linux to Windows
- 6 Answers 6
- Static compile sdl2
- Let’s cross-compile examples from rust-sdl2 project from Ubuntu to Windows x86_64
- Run in cmd.exe
- Features
- Dependencies
- Installation
- Usage
The Rust Programming Language
Установка
Первым шагом является установка Rust. Мы загрузим Rust, используя инструмент командной строки rustup , предназначенный для управлениями версиями Rust и другими связанными с ним инструментами. Вам понадобится интернет соединение для его загрузки.
Замечание: Если вы предпочтёте не использовать rustup по какой-то причине, пожалуйста, ознакомьтесь с другими вариантами на с странице the Rust installation page.
Следующие шаги устанавливают последнюю стабильную версию компилятора Rust. Стабильность Rust гарантирует, что все примеры в книге, которые компилируются, будут продолжать компилироваться с более новыми версиями Rust. Вывод может немного отличаться между версиями, потому что Rust часто улучшает сообщения об ошибках и предупреждения. Другими словами, любая более новая стабильная версия Rust, которую вы устанавливаете с помощью этих шагов, должна работать должным образом с содержанием этой книги.
Нотация командной строки
В данной главе и потом во всей книге мы покажем некоторые команды в терминале командной строки. Строки, которые нужно ввести в терминале, начинаются с $ . Вам не нужно вводить сам символ $ ; он только отображает, что это начало каждой команды. Строки, которые НЕ начинаются с $ , обычно показывают вывод предыдущей команды. В дополнение, специфичные для PowerShell примеры используют символ > вместо символа $ .
Установка rustup на Linux или macOS
Если вы используете Linux или macOS, пожалуйста, выполните следующую команду:
Команда скачивает скрипт и начинает установку инструмента rustup , одновременно с установкой последней стабильной версии Rust. Вас могут запросить ввести локальный пароль. При успешной установке вы увидите следующий вывод:
Дополнительно, вам нужен какой-то вариант программы «линковщика». Возможно какой-то у вас уже установлен, но если при попытке компиляции Rust программы вы получаете ошибки, что «линковщик» не смог выполнится, то это означает, что он не установлен в системе и вам необходимо установить его вручную. Компиляторы языка C обычно имеют в своём составе корректный линковщик. Поищите как установить на вашу платформу компилятор языка C. Также, некоторые общие Rust пакеты зависят от C кода и им тоже будет необходим компилятор C. Так что, имеет смысл его поставить сейчас.
Установка rustup на Windows
Для Windows, посетите ссылку https://www.rust-lang.org/tools/install и следуйте инструкциям для установки Rust. На некотором шаге установки вы можете получить сообщение, объясняющее необходимость инструментов сборки C++ для Visual Studio 2013 или более поздней версии. Самый простой способ получить их это инсталлировать Build Tools for Visual Studio 2019. Когда вас спросят, какие рабочие нагрузки установить, убедитесь, что выбраны «C++ build tools» и что включены Windows 10 SDK и компоненты пакета английского языка.
Остальные часть этой книги используют команды, работающие как в cmd.exe, так и в PowerShell. Есть некоторые отличия, которые мы объясним.
Обновление и удаление
После установки Rust с помощью rustup , обновление на последние версии выполняется с помощью следующего простого скрипта командой:
Чтобы удалить Rust и rustup , выполните
следующую команду:
Устранение возможных ошибок
Чтобы проверить, правильно ли у вас установлен Rust, откройте оболочку и введите эту строку:
Вы должны увидеть номер версии, хэш коммита и дату выпуска последней стабильной версии в следующем формате:
Если вы видите данную информацию, то вы установили всё успешно. Если нет и вы используете Windows, проверьте что путь к Rust находится в системной переменной %PATH% . Если он корректный, но Rust все ещё не работает, то есть множество мест, где можно получить помощь. Самое простое это канал #beginners официального Rust Discord сервера. Там можно списаться в другими пользователями Rust (Rustaceans — как мы себя называем) которые могут помочь. Другие хорошие ресурсы включают пользовательский форум и ресурс Stack Overflow.
Локальная документация
Установка Rust также включает локальную копию документации, поэтому вы можете читать её в автономном режиме. Запустите rustup doc , чтобы открыть локальную документацию в вашем браузере.
Каждый раз, когда тип или функция предоставляется из стандартной библиотеки и вы не знаете, что они делают или как их использовать, используйте документацию по интерфейсу прикладного программирования (API), чтобы узнать это!
Кросскомпиляция выполняемых файлов Rust для Windows из Linux
Наверное не будет уж очень удивительным если я тут, на IT площадке Хабра, скажу что я иногда балую себя программированием.
Основная OS у меня Linux, но иногда приходится собирать исполняемые файлы и для Windows. И естественно что перегружаться в Windows только для сборки exe не особо хочется. С языками C и C++ проблем нет, давно существует кросскомпилятор MinGW , который прекрасно с этим справляется. Про Python и Java даже упоминать не стоит, кроссплатформенность в них изначально. Но в прошлом году я решил попробовать такой пока что новомодный язык, как Rust. При сборке исполняемого файла при помощи включённого в дистрибутив Rust пакетного менеджера cargo вроде как достаточно задать ключ —target , при помощи которого указать результирующий процессор, архитектуру и ABI и при сборке из Linux в результате получить exe, который будет являться стандартным исполняемым файлом для Windows. Но пытаясь так сделать:
я получил только сообщения об ошибках линкера:
Если кому интересно как я это поборол и теперь спокойно могу кросскомпилировать программы на 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, которых в стандартном репозитории, естественно, нет.
Первым делом убеждаемся что у нас установлены необходимые цели, запустив следующую команду:
Получаем список всех возможных целей, и целей, которые у нас установлены:
Для создания исполняемых файлов для Windows из Linux нам необходимы цели i686-pc-windows-gnu для 32bit exe и x86_64-pc-windows-gnu для 64bit exe. Если данные цели не отмечены как (installed) , то доставляем их при помощи команды
После убеждаемся что у нас установлен кросскомпилятор MinGW , запустив
или другой пакетный менеджер для нашего дистрибутива Linux:
При отсутствии MinGW устанавливаем необходимые пакеты, запустив
Ну вот вроде бы теперь всё в наличии, далее будем решать проблемы по мере их появления (ага, можно сказать что это получается прям какой-то Test-Driven Development, 🙂
Создаём простейший проект на языке Rust:
Сначала компилируем и запускаем его как родное приложение Linux:
Всё работает. Теперь пробуем его собрать как цель x86_64-pc-windows-gnu :
и получаем всё то же сообщение об ошибке сборки:
Понятно, для сборки вызывается не линкер из MinGW , а уже установленный в системе gcc . Исправляем эту ситуацию, для этого создаём в проекте директорию .cargo и в ней файл config со следующим содержимым:
Это необходимо для того чтобы при сборке целей для Windows в качестве линкера использовался не установленный в системе gcc , а линкер из MinGW .
Пробуем собрать проект снова:
и получаем другую ошибку от линкера, уже от x86_64-w64-mingw32-gcc :
Дело в том, что Rust по-умолчанию собирает всё в статическом виде, поэтому кроме пакетов mingw32-winpthreads и mingw64-winpthreads , которые dnf автоматически установил как зависимости для mingw32-gcc и mingw64-gcc обязательно должны быть установлены пакеты статических библиотек mingw32-winpthreads-static и mingw64-winpthreads-static , без них линкер всё время будет жаловаться на отсутствующий -lpthread и сборка не пройдёт. Доустанавливаем недостающие пакеты:
и опять запускаем компиляцию:
Опять ошибка линковки! Но уже другая:
Линкер жалуется на отсутствующие символы __onexitbegin и __onexitend в файле
/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/crt2.o , который мы установили в составе цели x86_64-pc-windows-gnu . После некоторых раздумий, гугления, чтения доков на сайте Rust, изучения исходников самого Rust, того как и чем сам Rust собирается я понял: дело в том что сам Rust для Windows, и соответственно его компоненты для целей pc-windows-gnu, собраны с использованием MinGW 6.3.0, а у меня в Fedora Linux 31 версия MinGW 9.2.1, поэтому и происходит несоответствие в CRT. Ok, попробуем перенести crt2.o из федориного MinGW в директорию Rust для цели x86_64-pc-windows-gnu. И кроме crt2.o перенесём ещё и dllcrt2.o, который является точкой входа для динамических библиотек:
и опять запускаем компиляцию нашего проекта на 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.
Я не буду вдаваться в подробности как именно пересобирать MinGW , это уже не так сложно и не так интересно ( configure там надо запускать с параметром —disable-sjlj-exceptions , остальное тривиально), скажу только одно: после того как MinGW пересобран с разматыванием стека Dwarf вместо SJLJ оттуда надо взять всего один файл под названием libgcc_eh.a и положить его в директорию с библиотеками для цели i686-pc-windows-gnu . После этого проекты в которых используются паникующие функции начнут собираться не только для 64bit целей Windows, но и для 32bit:
Cross-compile a Rust application from Linux to Windows
Basically I’m trying to compile the simplest code to Windows while I am developing on Linux.
I found these commands by searching the internet:
Sadly, none of them work. It gives me an error about the std crate missing
Is there a way to compile code on Linux that will run on Windows?
6 Answers 6
Other answers, while technically correct, are more difficult than they need to be. There’s no need to use rustc (in fact it’s discouraged, just use cargo ), you only need rustup , cargo and your distribution’s mingw-w64.
Add the target (you can also change this for whatever target you’re cross compiling for):
You can build your crate easily with:
No need for messing around with
/.cargo/config or anything else.
EDIT: Just wanted to add that while you can use the above it can also sometimes be a headache. I wanted to add that the rust tools team also maintains a project called cross: https://github.com/rust-embedded/cross This might be another solution that you want to look into
The Rust distribution only provides compiled libraries for the host system. However, according to Arch Linux’s wiki page on Rust, you could copy the compiled libraries from the Windows packages in the download directory (note that there are i686 and x86-64 packages) in the appropriate place on your system (in /usr/lib/rustlib or /usr/local/lib/rustlib , depending on where Rust is installed), install mingw-w64-gcc and Wine and you should be able to cross-compile.
If you’re using Cargo, you can tell Cargo where to look for ar and the linker by adding this to
/.cargo/config (where $ARCH is the architecture you use):
Note: the exact paths can vary based on your distribution. Check the list of files for the mingw-w64 package(s) (GCC and binutils) in your distribution.
Then you can use Cargo like this:
UPDATE 2019-06-11
This fails for me with:
Static compile sdl2
There is option to static-compile sdl but it didn’t work for me.
Let’s cross-compile examples from rust-sdl2 project from Ubuntu to Windows x86_64
Build examples at once
Or stop after first fail:
cargo build will put binaries in target/x86_64-pc-windows-gnu/debug/examples/
Copy needed files:
Then copy directory target/x86_64-pc-windows-gnu/debug/examples/ to your Windows machine and run exe files.
Run in cmd.exe
If you want to see the console output when running exe files, you may run them from cmd.exe .
To open cmd.exe in current directory in file explorer, right click with shift on empty place in window and choose Open command window here .
Backtraces with mingw should work now — if not use msvc https://github.com/rust-lang/rust/pull/39234
/rust-sdl), (b) it uses the tip of the master branch of rust-sdl2, which no longer works with SDL2 2.0.4, and (c) sine.wav has moved. But after some minor fixes it does indeed work! – Tom Anderson Jan 11 ’19 at 10:13
There is Docker based solution called cross. All the required tools are in virtualized environment so you don’t need to install additional packages for your machine. See Supported targets list.
From project’s README:
Features
- cross will provide all the ingredients needed for cross compilation without touching your system installation.
- cross provides an environment, cross toolchain and cross compiled libraries, that produces the most portable binaries.
- “cross testing”, cross can test crates for architectures other than i686 and x86_64.
- The stable, beta and nightly channels are supported.
Dependencies
- rustup
- A Linux kernel with binfmt_misc support is required for cross testing.
One of these container engines is required. If both are installed, cross will default to docker.
- Docker. Note that on Linux non-sudo users need to be in the docker group. Read the official post-installation steps. Requires version 1.24 or later.
- Podman. Requires version 1.6.3 or later.
Installation
Usage
cross has the exact same CLI as Cargo but as it relies on Docker you’ll have to start the daemon before you can use it.
I’ve had success on Debian (testing) without using Mingw and Wine just following the official instructions. They look scary, but in the end it didn’t hurt that much.
The official instructions also contain info on how to cross-compile C/C++ code. I haven’t needed that, so it’s something I haven’t actually tested.
A couple of remarks for individual points in the official instructions. The numbers match the numbers in the official instructions.
- Debian: sudo apt-get install lld
- Make a symlink named lld-link to lld somewhere in your $PATH. Example: ln -s /usr/bin/lld local_bin/lld-link
- I don’t cross-compile C/C++, haven’t used this point personally.
This is probably the most annoying part. I installed Rust on a Windows box via rustup, and copied the libraries from the directories named in the official docs to the Linux box. Beware, there were sometimes uppercase library filenames, but lld wants them all lowercase (Windows isn’t case-sensitive, Linux is). I’ve used the following to rename all files in current directory to lowercase:
Personally, I’ve needed both Kit directories and just one of the VC dirs.
- rustup target add i686-pc-windows-msvc
- rustup target add x86_64-pc-windows-msvc
For cross-building itself, I’m using the following simple script (32-bit version):
I’m using the script the same way I would use cargo build