1. 1. Introduction
  2. 2. Введение
  3. 3. C чего начать
  4. 4. Изучение Rust
    1. 4.1. Угадайка
    2. 4.2. Обедающие философы
    3. 4.3. Вызов кода на Rust из других языков
  5. 5. Синтаксис и семантика
    1. 5.1. Связывание имён
    2. 5.2. Функции
    3. 5.3. Простые типы
    4. 5.4. Комментарии
    5. 5.5. Конструкция `if`
    6. 5.6. Циклы
    7. 5.7. Владение
    8. 5.8. Ссылки и заимствование
    9. 5.9. Время жизни
    10. 5.10. Изменяемость
    11. 5.11. Структуры
    12. 5.12. Перечисления
    13. 5.13. Конструкция `match`
    14. 5.14. Шаблоны сопоставления `match`
    15. 5.15. Синтаксис методов
    16. 5.16. Вектора
    17. 5.17. Строки
    18. 5.18. Обобщённое программирование
    19. 5.19. Типажи
    20. 5.20. Типаж `Drop`
    21. 5.21. Конструкция `if let`
    22. 5.22. Типажи-объекты
    23. 5.23. Замыкания
    24. 5.24. Универсальный синтаксис вызова функций
    25. 5.25. Контейнеры и модули
    26. 5.26. `const` и `static`
    27. 5.27. Атрибуты
    28. 5.28. Псевдонимы типов
    29. 5.29. Приведение типов
    30. 5.30. Ассоциированные типы
    31. 5.31. Безразмерные типы
    32. 5.32. Перегрузка операций
    33. 5.33. Преобразования при разыменовании
    34. 5.34. Макросы
    35. 5.35. Сырые указатели
    36. 5.36. Небезопасный код
  6. 6. Эффективное использование Rust
    1. 6.1. Стек и куча
    2. 6.2. Тестирование
    3. 6.3. Условная компиляция
    4. 6.4. Документация
    5. 6.5. Итераторы
    6. 6.6. Многозадачность
    7. 6.7. Обработка ошибок
    8. 6.8. Выбор гарантий
    9. 6.9. Интерфейс внешних функций
    10. 6.10. Типажи `Borrow` и `AsRef`
    11. 6.11. Каналы сборок
    12. 6.12. Using Rust without the standard library
  7. 7. Нестабильные возможности Rust
    1. 7.1. Плагины к компилятору
    2. 7.2. Встроенный ассемблерный код
    3. 7.3. Без stdlib
    4. 7.4. Внутренние средства
    5. 7.5. Элементы языка
    6. 7.6. Продвинутое руководство по компоновке
    7. 7.7. Тесты производительности
    8. 7.8. Синтаксис упаковки и шаблоны `match`
    9. 7.9. Шаблоны `match` для срезов
    10. 7.10. Ассоциированные константы
    11. 7.11. Пользовательские менеджеры памяти
  8. 8. Глоссарий
  9. 9. Syntax Index
  10. 10. Библиография

Продвинутое руководстве по компоновке (advanced linking)

Распространённые ситуации, в которых требовалась компоновка с кодом на Rust, уже были рассмотрены в предыдущих главах книги. Однако для поддержки прозрачного взаимодействия с нативными библиотеками требуется более широкая поддержка разных вариантов компоновки.

Аргументы компоновки (link args)

Есть только один способ тонкой настройки компоновки — атрибут link_args. Этот атрибут применяется к блокам extern, и указывает сырые аргументы, которые должны быть переданы компоновщику при создании артефакта. Например:

#![feature(link_args)]

#[link_args = "-foo -bar -baz"]
extern {}Run

Обратите внимание, что эта возможность скрыта за feature(link_args), так как это нештатный способ компоновки. В данный момент rustc вызывает системный компоновщик (на большинстве систем это gcc, на Windows — link.exe), поэтому передача аргументов командной строки имеет смысл. Но реализация не всегда будет такой — в будущем rustc может напрямую использовать LLVM для связывания с нативными библиотеками, и тогда link_args станет бессмысленным. Того же эффекта можно достигнуть с помощью передачи rustc аргумента -C link-args.

Крайне рекомендуется не использовать этот атрибут, и пользоваться вместо него более точно определённым атрибутом #link(...) для блоков extern.

Статическое связывание

Статическое связывание — это процесс создания артефакта, который содержит все нужные библиотеки, и потому не потребует установленных библиотек на целевой системе. Библиотеки на Rust по умолчанию связываются статически, поэтому приложения и библиотеки на Rust можно использовать без установки Rust повсюду. Напротив, нативные библиотеки (например, libc и libm) обычно связываются динамически, но это можно изменить, и сделать чтобы они также связывались статически.

Компоновка — это процесс, который реализуется по-разному на разных платформах. На некоторых из них статическое связывание вообще не возможно! Этот раздел предполагает знакомство с процессом компоновки на вашей платформе.

Linux

По умолчанию, программы на Rust для Linux компонуются с системной libc и ещё некоторыми библиотеками. Давайте посмотрим на пример на 64-битной машине с Linux, GCC и glibc (самой популярной libc на Linux):

$ cat example.rs
fn main() {}
$ rustc example.rs
$ ldd example
        linux-vdso.so.1 =>  (0x00007ffd565fd000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa81889c000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa81867e000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa818475000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa81825f000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa817e9a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fa818cf9000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa817b93000)

Иногда динамическое связывание на Linux нежелательно: например, если вы хотите использовать возможности из новых библиотек на старых системах или на целевых системах нет таких библиотек.

Статическое связывание возможно с альтернативной libc, musl. Вы можете скомпилировать свою версию Rust, которая будет использовать musl, и установить её в отдельную директорию, с помощью инструкции, приведённой ниже:

$ mkdir musldist
$ PREFIX=$(pwd)/musldist
$
$ # Build musl
$ wget http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
[...]
$ tar xf musl-1.1.10.tar.gz
$ cd musl-1.1.10/
musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX
[...]
musl-1.1.10 $ make
[...]
musl-1.1.10 $ make install
[...]
musl-1.1.10 $ cd ..
$ du -h musldist/lib/libc.a
2.2M    musldist/lib/libc.a
$
$ # Build libunwind.a
$ wget http://llvm.org/releases/3.6.1/llvm-3.6.1.src.tar.xz
$ tar xf llvm-3.6.1.src.tar.xz
$ cd llvm-3.6.1.src/projects/
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk/ libcxxabi
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libunwind/trunk/ libunwind
llvm-3.6.1.src/projects $ sed -i 's#^\(include_directories\).*$#\0\n\1(../libcxxabi/include)#' libunwind/CMakeLists.txt
llvm-3.6.1.src/projects $ mkdir libunwind/build
llvm-3.6.1.src/projects $ cd libunwind/build
llvm-3.6.1.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
llvm-3.6.1.src/projects/libunwind/build $ make
llvm-3.6.1.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
llvm-3.6.1.src/projects/libunwind/build $ cd cd ../../../../
$ du -h musldist/lib/libunwind.a
164K    musldist/lib/libunwind.a
$
$ # Build musl-enabled rust
$ git clone https://github.com/rust-lang/rust.git muslrust
$ cd muslrust
muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX
muslrust $ make
muslrust $ make install
muslrust $ cd ..
$ du -h musldist/bin/rustc
12K     musldist/bin/rustc

Теперь у вас есть сборка Rust с musl! Поскольку мы установили её в отдельную корневую директорию, надо удостовериться в том, что система может найти исполняемые файлы и библиотеки:

$ export PATH=$PREFIX/bin:$PATH
$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH

Давайте попробуем!

$ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs
$ rustc --target=x86_64-unknown-linux-musl example.rs
$ ldd example
        not a dynamic executable
$ ./example
hi!
thread '<main>' panicked at 'failed', example.rs:1

Успех! Эта программа может быть скопирована на почти любую машину с Linux с той же архитектурой процессора и будет работать без проблем.

cargo build также принимает опцию --target, так что вы можете собирать контейнеры как обычно. Однако, возможно вам придётся пересобрать нативные библиотеки с musl, чтобы иметь возможность скомпоноваться с ними.