Rust: Связь с LLD

Созданный на 17 февр. 2017  ·  94Комментарии  ·  Источник: rust-lang/rust

LLVM 4.0 поставляется с включенным LLD, хотя AFAIK еще не готов к производству на всех платформах. Я считаю, что в ближайшее время у нас запланировано обновление LLVM для решения проблем AVR / emscripten в любом случае, так что теперь самое время начать определять, что нам может потребоваться для его поддержки, как это влияет на производительность компилятора / размер двоичного файла / производительность времени выполнения по сравнению с нашим обычные компоновщики и на каких платформах мы могли бы включить его по умолчанию.

Текущий статус (2020-04-24) резюмирован на https://github.com/rust-lang/rust/issues/39915#issuecomment -618726211

A-linkage C-feature-request I-compiletime T-compiler

Самый полезный комментарий

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

Что такое lld

Компоновщик, являющийся частью проекта llvm, что желательно по двум причинам:

  • это очень удобно для кросс-компиляции (отсюда и упор на встроенные цели)
  • это очень быстро (часто выполняется вдвое быстрее, чем Gold - связывание может занять несколько минут для больших проектов (rustc, servo и т. Большое дело.)

Что Rust делает с lld сегодня

  • В настоящее время Rust поставляет свою собственную копию lld на большинстве платформ в виде двоичного файла, который он называет rust-lld.
  • rust-lld используется по умолчанию для многих целей без операционной системы
  • rust-lld используется по умолчанию для wasm
  • (?) вы можете явно запросить использование rust-lld с помощью "-C linker-flavour" (неясно, что именно это делает на платформах, отличных от голого металла, см. ниже)

Проблемы с использованием rust-lld в других местах (например, настольный linux / mac / windows)

  • Бэкэнд macOS (Mach-O) для lld сломан и заброшен

    • началось переписывание с нуля, но это только начало

  • На платформах linux / unix вы не должны напрямую вызывать ld / lld. Вы должны вызвать компоновщик через системный компилятор c (т.е. gcc), в обязанности которого входит обнаружение системных символов, таких как crt1.o, и их передача ld. Это означает, что мы не можем «просто» использовать rust-lld; мы должны передать его в gcc / clang / something. (мы не хотим сами реализовывать эту системную символьную логику)

    • Как правило, вы не можете указать компоновщик в качестве пути, вы должны вставить его в путь поиска компилятора C как "ld"

    • В качестве альтернативы вы можете сделать то же самое, но ввести его как «ld.lld» и передать «-fuse-ld = lld»



      • Это может быть важно, очевидно, lld выполняет определение двоичного имени в стиле clang, если оно выполняется как «ld» или «ld.lld» (требуется исследование)


      • К сожалению, -fuse-ld = lld является только частью GCC 9, поэтому нам может потребоваться определение функции / версии для его использования (у clang это уже давно)



  • windows-msvc, по- видимому, в хорошей форме и, похоже, имеет некоторую ограниченную поддержку использования rust-lld в бэкэнде, но я не понимаю, что здесь нужно сделать.
  • windows-mingw, похоже, находится примерно в том же месте, что и linux / unix, за исключением того, что вы можете получить древний GCC, и все немного шатко, потому что псевдо-windows-linux не совсем хорошо протестированная конфигурация?

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

Я написал две метабуга для целенаправленных усилий по использованию (rust-) lld по умолчанию на двух платформах:

  • # 71515 - x64 Ubuntu 20.04 LTS (и в более широком смысле все платформы x64 ELF)
  • # 71520 - окна x64 msvc

Все 94 Комментарий

См. Также PoC в # 36120.

LLD может быть очень хорошим кандидатом для целей MinGW, потому что в настоящее время мы все равно связываем с ними компоновщик, а компоновщик MinGW имеет множество проблем, начиная от отсутствия ASLR и заканчивая отсутствием поддержки bigobj. Если мы сможем каким-то образом использовать необходимые библиотеки mingw при кросс-компиляции, а не только для нативного таргетинга (которым в настоящее время ограничен пакет mingw в rustup), то это позволило бы кросс-компиляцию rust из linux из коробки, что было бы огромным улучшением. над существующей ситуацией, когда люди получают MinGW из своего дистрибутива, а затем сталкиваются с проблемами, потому что дистрибутивы почти всегда используют несовместимый MinGW.

LLD не является хорошим кандидатом для изначально нацеливания на цели MSVC по нескольким причинам, основной из которых является отсутствие поддержки debuginfo. Для кросс-компиляции с целевыми объектами MSVC требуются библиотеки, которые нельзя распространять, поэтому мы все равно не можем поддерживать это из коробки.

Проблема отслеживания при обновлении до LLVM 4.0: https://github.com/rust-lang/rust/issues/37609 .

Для справки, lld определенно не готов для целей Solaris. Но в Solaris я не знаю причин для использования lld вместо собственного ld. Мы уже рассмотрели, что потребуется, чтобы ржавчина использовала Solaris ld на Solaris вместо использования gcc для компоновки.

@binarycrusader Одна из причин использовать lld - это сборка для Solaris, а не для Solaris.

PR rust-lang / rust # 40018 добавляет к rustc флаг -Z linker-flavor чтобы сделать возможным использование LLD в качестве компоновщика. Этот PR не встраивает LLD в rustc, но позволяет экспериментировать с ним вне дерева.

@binarycrusader ^, который может помочь в вашем эксперименте по прямому использованию ld Solaris вместо gcc.

Теперь мы работаем на LLVM 4.0. @japaric , означает ли это, что флаг компоновщика теперь можно легко использовать для сравнения и сопоставления LLD с системным компоновщиком?

@bstrie # 40018 приземлился несколько недель назад. С тех пор, как он приземлился, можно было использовать -Z linker-flavor=ld -C linker=ld.lld для использования внешнего двоичного файла LLD в качестве компоновщика. Обратите внимание, что, в отличие от gcc, LLD не знает, где находятся системные библиотеки, поэтому вам придется передать путь поиска библиотеки компоновщику с помощью -C link-args='-L ...' если вы связываетесь с какой-либо системной библиотекой.

В чем помогает LLVM 4.0, так это в слиянии LLD с rustc. С этим изменением нам не потребуется внешний компоновщик в некоторых сценариях, таких как связывание двоичных файлов MUSL или программ на «голом железе». Я говорю о некоторых сценариях, потому что для большинства целей требуется связывание с системными библиотеками, где вы столкнетесь с проблемой пути поиска библиотеки, о которой я упоминал выше. Для этих целей LLD не работает из коробки. Непонятно, как и где решить эту проблему, и без решения для этого мы не можем переключиться на LLD для наиболее важных целей (уровень 1), что в первую очередь снижает привлекательность встраивания LLD в rustc.

@japaric Каковы аргументы против встраивания (относительной sysroot библиотеки) путей поиска, а также таких вещей, как -lc -lpthread crt0.o , непосредственно в rustc? В конце концов, какой-то компонент инструментальной цепочки должен встраивать их, поскольку у нас нет какого-либо стандарта для платформ, которому следует следовать, а binutils не является хорошим золотым источником этих знаний.

Единственный недостаток, о котором я могу думать, - это ситуация, когда одна и та же тройка будет иметь разные пути поиска на разных типах систем (что, вероятно, будет эксклюзивным для троек Linux / glibc и особенно плохо на платформах с Multilib). В этом случае я считаю, что clang отслеживает имя ОС и жестко кодирует соглашения, специфичные для ОС, что кажется плохим, но, вероятно, неизбежным, если кто-то хочет распространять один двоичный файл, который работает на любом Linux (и не требует системного компоновщика).

@ retep998 Несколько месяцев назад я

Надеюсь, я ошибаюсь.

Пометить это как ошибку производительности, поскольку, согласно тестам LLD, кажется, что он превосходит GNU ld в десять раз, а производительность компоновки в настоящее время является важным компонентом скорости компилятора.

Эээ, забыл связать тесты: https://lld.llvm.org/#performance

(Актуально сегодня, так как LLVM 5.0 только что был выпущен.)

Связывание с LLD происходит намного быстрее, чем с bfd или gold, но я сомневаюсь, что его использование значительно улучшит общую производительность. Тем не менее, я считаю, что этот вопрос важен и должен быть приоритетным.

@tpimh Я на самом деле не совсем уверен, должен ли тег I-slow представлять ошибки производительности во время выполнения или ошибки производительности во время компиляции, я имел в виду последнее. И IME, когда я смотрю на временные проходы, связывание вывода обычно находится в трех самых длинных фазах, значительно длиннее, чем большинство, поэтому даже сокращение времени связывания вдвое, вероятно, было бы огромной победой (особенно для больших вещей, таких как Servo и rustc).

@bstrie I-slow - для плохой производительности во время выполнения, I-compiletime - для производительности компилятора в последний раз, когда я проверял

Хорошие новости для всех, кто интересуется малоизвестной темой перекрестных ссылок с Linux на Windows. Я сказал ранее, что это невозможно с lld, но это верно только для вкуса ld ld. Это возможно для lld's link.exe (lld-link).

Специально для Rust мы можем сделать это сегодня с парой изменений кода.

  1. Нам нужно скомпилировать очень небольшое подмножество CRT mingw-w64 в объектные файлы .o. А именно инициализация локального хранилища какого-то потока. Еще нам понадобится chkstk.

  2. lld не любит обычные библиотеки импорта MinGW. Вместо этого нам нужно самостоятельно встроить файлы .def в файлы .lib, используя lld-link или llvm-dlltool.

  3. Измените lld для обработки IMPORT_NAME_NOPREFIX как
    IMPORT_NAME_UNDECORATE, потому что даже на шаге 2 .libs не идеальны

  4. Измените seh.rs Rust, чтобы заменить TYPE_INFO_VTABLE на ptr :: null (). Требуется, поскольку символ ??_7type_info@@6B@ не определен в MinGW. Затем соберите и установите Rust.

  5. Используйте .cargo / config, чтобы указать пользовательский сценарий оболочки в качестве компоновщика.

  6. Наш сценарий компоновщика оболочки должен вызывать lld-link в основном с использованием переданных ему параметров. Однако мы должны сделать несколько настроек:

    a) Исправьте регистр имени файла, например, измените AdvAPI32.Lib на advapi32.lib

    б) Измените файл .def, который генерирует Rust, добавив в символы префикса дополнительное подчеркивание.

    c) Отменить точку входа (/ entry). Требуется, вероятно, из-за проблемы с изменением имени.

    d) Добавьте объектные файлы mingw-crt, которые вы скомпилировали на шаге 1.

  7. Создайте свой проект Rust с помощью xargo --target = i686-pc-windows-msvc

Выполнение вышеуказанных шагов позволяет мне кросс-компилировать код Rust. Я могу даже запаниковать и поймать панику, используя раскручивание Rust на основе SEH.

@iainnicol Вы смешиваете цель msvc с битами MinGW, поэтому вам нужно делать все эти странные модификации. Если вы просто скопируете библиотеки из существующей установки VC ++, вы сможете использовать lld-link как обычно, без всех этих модификаций или каких-либо битов MinGW.

Но я не хочу использовать существующую установку VC ++. Невозможно получить его, не потратив примерно восемь часов на загрузку и установку мусора, не говоря уже о его повторном распространении.

Автономные инструменты сборки намного легче, если это уже не то, о чем вы говорите, и в этом случае, возможно, нам следует поработать над улучшением или воссозданием того, что сделал MinGW, чтобы он действительно был совместим с MSVC.

Автономные инструменты сборки намного легче

Я не понимал, что Microsoft их распространяет. Не могли бы вы дать ссылку на них? Есть ли какой-нибудь разумный способ распаковать установочный архив без его запуска, то есть это msi или что-то подобное?

Вот они: http://landinghub.visualstudio.com/visual-cpp-build-tools

Обе версии 2015 и 2017 являются exes, но вы можете убедить exe 2017 года дать вам то, что вы хотите, с помощью этого: https://docs.microsoft.com/en-us/visualstudio/install/install-vs- сеть несовместимого качества

Если мы действительно хотим сделать это правильно для Windows, нам в первую очередь понадобится https://github.com/rust-lang/rust/issues/30027, чтобы исключить необходимость в Windows SDK или библиотеках импорта MinGW. Тогда все, что нам осталось бы, это заменить биты CRT нашими собственными чистыми версиями Rust (математические функции / функции памяти, точка входа, несколько других битов времени выполнения, которые нужны Rust), и у нас будет полностью автономная инструментальная цепочка Rust, которая может создавать двоичные файлы Windows! Обратной стороной этого является то, что вы не сможете статически связать код C / C ++, потому что это очень сильно зависит от связывания в соответствующем CRT из MinGW или VC ++. Конечно, весь смысл Rust состоит в том, чтобы переписать все на Rust, так что это не такая уж большая проблема.

Хорошие новости для всех, кто интересуется малоизвестной темой перекрестных ссылок с Linux на Windows. Я сказал ранее, что это невозможно с lld, но это верно только для вкуса ld ld. Это возможно для lld's link.exe (lld-link).

Похоже, теперь это должно быть возможно и с ароматом ld: https://reviews.llvm.org/rL312926

MinGW-совместимый драйвер нового lld является оболочкой для компоновщика lld-link. Он внутренне переводит параметры Unix-ish в параметры Windows-ish, а затем вызывает точку входа lld-link. Я не уверен, хотите ли вы его использовать, потому что (за исключением того, что драйвер-оболочка неполный и не готов к использованию), это не упрощает задачу, если у вас еще нет Makefiles для MinGW.

У меня к вам (наверное, глупый) вопрос о кросс-компиляции. В Windows все символы, импортированные из dllimport, имеют имена DLL, из которых они импортируются. Если у вас нет файлов библиотеки MSVC, как узнать, из каких файлов импортируются символы, импортируемые dllimport?

У меня к вам (наверное, глупый) вопрос о кросс-компиляции. В Windows все символы, импортированные из dllimport, имеют имена DLL, из которых они импортируются. Если у вас нет файлов библиотеки MSVC, как узнать, из каких файлов импортируются символы, импортируемые dllimport?

Если у вас нет библиотек импорта, вам нужно либо создать библиотеки импорта, либо реализовать https://github.com/rust-lang/rust/issues/30027, чтобы winapi мог делать все тяжелые работа по определению того, из какой DLL происходит каждый символ, а также занудство вроде порядковых номеров. Что-то должно указывать сопоставление символов во время компоновки с символами / порядковыми номерами в библиотеках DLL, будь то библиотеки импорта или аннотации в вашем коде.

После загрузки https://reviews.llvm.org/rL311734 я почти могу загрузить rustc с помощью lld в macOS. Похоже, есть проблема с метаданными dylib, которую мне все еще нужно исследовать.

У меня есть ветка, которая воскрешает https://github.com/rust-lang/rust/pull/36120; поскольку нам нужно это (самое последнее) исправление lld, оно заблокировано на https://github.com/rust-lang/rust/issues/43370.

@tamird : # 43370 закрыт.

LLD был добавлен в https://github.com/rust-lang/rust/pull/48125 и теперь поставляется с платформами уровня 1 (mac, linux, windows). Вы можете протестировать его с помощью -Z linker-flavor для каждой платформы, хотя по умолчанию он вряд ли будет работать для большинства платформ. Однако по умолчанию он работает в MSVC. Например:

$ RUSTFLAGS='-Z linker-flavor=lld-link' cargo build

уменьшено собственное время связывания Cargo с 2,5 до 1,5, хорошее улучшение!

@alexcrichton , каковы следующие шаги? В идеале у нас должен быть LLD, работающий по умолчанию на всех платформах (я не представляю, сколько работы это займет), а затем я хотел бы запустить тесты времени компиляции / времени выполнения, чтобы увидеть, имеет ли смысл использовать LLD по умолчанию на любые платформы. Производительность компоновки будет важнее, чем когда-либо, особенно при инкрементной компиляции.

Производительность компоновки будет важнее, чем когда-либо, особенно при инкрементной компиляции.

Жаль, что производительность связывания все еще недостаточно важна для нас, чтобы делать такие вещи, как включение дополнительных ссылок на платформах, которые его поддерживают. https://github.com/rust-lang/rust/issues/37543

@bstrie Полагаю, это следующие шаги, чтобы заставить его работать на других платформах :)

Что касается того, что это влечет за собой, я не уверен, но он уже работает на MSVC, я думаю, что он далек от работы на MinGW / Linux, и мы довольно близки к OSX. Что касается кросс-архитектурной поддержки, я тоже не уверен. Я не думаю, что в ближайшем будущем мы «стабилизируем» его для чего-либо, кроме платформы wasm.

@alexcrichton Могу я спросить, как бы вы указали «стабилизацию»? Почему не было возможности «стабилизировать» связывание с lld для других основных платформ, поддерживаемых ржавчиной? (например, кросс-компиляция исполняемого файла из linux для macOS).

Прямо сейчас такая сложная задача для кросс-компиляции, например, работа, необходимая для кросс-компиляции исполняемого файла для macOS (x86_64-apple-darwin) из Linux, требует нетривиальных шагов, таких как получение xcode sdk и создание всей цепочки инструментов.

@cynecx хороший вопрос! Об одном я не особо задумывался. Однако я думаю, что мы не хотим де-факто стабилизировать LLD только потому, что мы добавили его для другой платформы, это потребует времени и усилий, чтобы сделать это правильно и хорошо раскрыть.

например, работа, необходимая для кросс-компиляции исполняемого файла для macOS (x86_64-apple-darwin) из Linux, требует нетривиальных шагов, таких как получение xcode sdk и создание всей цепочки инструментов.

LLD здесь не поможет, вам все еще нужен Xcode SDK, потому что у него есть заголовки, которые вы не можете распространять (и в зависимости от того, что вы создаете, вам также понадобятся другие инструменты SDK).

Что действительно хорошо в том, что LLD теперь встроен в каждую ночь, так это то, что вы можете легко кросс-компилировать проекты на чистом Rust из Windows в Linux с помощью RUSTFLAGS='-Z linker-flavor=ld.lld' cargo build --target x86_64-unknown-linux-musl . Отлично подходит для написания небольших инструментов для Linux-машин, на которые нельзя просто установить Rust.

Я не думаю, что в ближайшем будущем мы «стабилизируем» его для чего-либо, кроме платформы wasm.

Как сказал @rkarp , очень распространенный вариант использования - нацеливание на x86_64-unknown-linux-musl (и, в конечном итоге, на steed) для поддержки контейнерных рабочих нагрузок Linux. Это одна из тех вещей, которые Go делает действительно хорошо, и мы, кажется, очень близки к тому, чтобы Rust мог делать то же самое. Что касается фактического использования, я уверен, что LLD для x86_64-unknown-linux-musl на самом деле будет использоваться гораздо шире, чем wasm.

В более общем плане, когда дело доходит до кросс-билдинга, я не думаю, что подход «он должен работать для всех хостов и / или всех целей» имеет смысл. Я думаю, что имеет смысл стабилизировать это для каждой цели по мере того, как цели начинают работать.

В частности, я хотел бы помочь с усилием по стабилизации LLD для целевой x86_64-unknown-linux-musl как можно скорее.

В моем проекте 37 ящиков, а в сборке содержится около 70 двоичных файлов (множество тестов). Ненаучно (наблюдая за top ) по крайней мере половину времени сборки мы выполняем только ld. Я ожидаю, что использование lld значительно ускорит нашу сборку. Мы на стабильном Rust, и мне еще не удалось заставить работать lld 6.0.

@briansmith вы тестировали LLD для musl и вашего -Z linker-flavor=ld.lld , и если это сработает, мы можем изменить значения по умолчанию!

@rocallahan, просто чтобы подтвердить, что вы сейчас используете золотой линкер, верно? (поскольку afaik это быстрее, чем стандартный компоновщик binutils). Если -Z linker-flavor=ld.lld работает (и быстрее), мы могли бы попытаться стабилизировать его, возможно! На какой платформе это было?

Ненаучно (как следует) по крайней мере половину времени сборки мы запускаем только ld.

Это для отладочной сборки BTW.

вы все используете золотой линкер, верно? (поскольку afaik это быстрее, чем стандартный компоновщик binutils)

Нет, это системный компоновщик Fedora, стандартный компоновщик GNU.

На какой платформе это было?

Fedora 27, четырехъядерный ноутбук Skylake с твердотельным накопителем. Я получу некоторые показатели производительности.

Хорошо знать! Сборки отладки, вероятно, получат наибольшую выгоду от времени компоновки от split dwarf (https://github.com/rust-lang/rust/issues/34651), а не от улучшений компоновщика.

Тем не менее, для информации о времени: @rocallahan, если у вас есть шанс проверить сознание с помощью ld.gold и ld.lld ?

Конечно. Я также должен напомнить, что проблема № 48762 - очень слабая задача для ускорения времени компоновки отладки Linux. (Мы уже используем взломанный скрипт компоновщика, который удаляет .debug_pubnames / .debug_pubtypes из исполняемого файла.)

Разделение DWARF может быть полезным, но также может вызвать проблемы для пользователей. Я прокомментирую в этом выпуске.

@briansmith вы тестировали LLD для musl и вашего

Хорошо, я протестирую. Возможно, изначально должна быть золотая середина между «по умолчанию» и «только по ночам», какой-то способ выбрать использование LLD, как мы можем с -Z , но без использования -Z чтобы он работал в стабильных сборках.

но без использования -Z, чтобы он работал в стабильных сборках.

Вы можете попробовать RUSTC_BOOTSTRAP=1 RUSTFLAGS="-Z linker-flavor=foo" cargo build

Пожалуйста, не рекомендуем использовать флаг начальной загрузки? Я опасаюсь, что если на него будет опираться достаточно проектов, ситуация станет де-факто стабильной, нарушив суть всего механизма стабильности.

Извините = /

В качестве точки данных, связывание ящика rustc_trans в самом репозитории Rust резко упало с 78 секунд до 1 секунды на моем локальном компьютере.

Моя производительность обусловлена ​​изменением пробелов в ящике в нижней части иерархии ящиков. Четырехъядерный ноутбук Skylake, 16 ГБ ОЗУ, rustc 1.24.0, LLD 7.0.0, GNU ld 2.29-13. Мы используем собственный сценарий компоновщика, который отбрасывает .debug_pubnames и .debug_pubtypes ; LLD использует совершенно разные пути кода при наличии сценария компоновщика, так что это может повлиять на ситуацию.

GNU ld:

real    2m39.138s
user    8m18.992s
sys 1m37.513s

LLD:

real    2m19.164s
user    6m4.477s
sys 0m56.858s

Золото не сработало, оно заблокировало наш скрипт компоновщика. Результаты достаточно стабильные. LLD не так сильно влияет на сквозное время, но значительно снижает загрузку ЦП; Я предполагаю, что это означает, что наша сборка не тратит много времени на ожидание завершения lds, но зато тратит много времени процессора на их запуск.

См. # 50584, где приведен реальный пример, в котором при переходе с GNU ld на lld обычная рабочая нагрузка "незначительное изменение и перестройка" выполняется более чем в 2,5 раза быстрее.

Er https://github.com/rust-lang/rust/issues/50584#issuecomment -400918647 здесь более уместен:


Следующим шагом для стабилизации LLD будет установка флага, например -Z linker-flavour = lld, работающего для всех целей (Windows + Mac + Linux). Он будет делать все, что нужно, для работы на различных платформах.

Как только это будет сделано, мы сможем прорекламировать это сообществу, попросив обратной связи. Здесь мы можем получить как информацию о времени, так и отчеты об ошибках для отправки в LLD. Если все идет гладко (что сомнительно с совершенно новым компоновщиком, но эй, вы никогда не знаете!), Мы можем включить его по умолчанию, в противном случае мы можем работать над стабилизацией выбора LLD, а затем добавить опцию в Cargo. toml, чтобы проекты могли хотя бы подписаться на него.

Мы перешли на lld для некоторых целей: https://rust-embedded.github.io/blog/2018-08-2x-psa-cortex-m-breakage/

Я тоже верю за васма?

Охватывает ли эта проблема как связывание с внешним двоичным файлом lld, так и соединение с внутренней поддержкой lld, встроенной в сам rustc? Или только первое?

Охватывает ли эта проблема как связывание с внешним двоичным файлом lld, так и соединение с внутренней поддержкой lld, встроенной в сам rustc? Или только первое?

Просто внешний двоичный файл lld, IIUC.

@nnethercote Есть ли еще одна проблема с отслеживанием использования внутреннего компоновщика, или мне следует подать отдельную проблему для этого?

Я раньше не слышал об идее внутреннего компоновщика. Я не знаю пиара для этого.

https://github.com/rust-lang/rust/pull/57514 подготовил почву для использования LLD для связывания LLVM.

Возможно, изначально должна быть золотая середина между «по умолчанию» и «только по ночам», какой-то способ выбрать использование LLD, как мы можем с -Z, но без использования -Z, чтобы он работал в стабильных сборках.

https://github.com/rust-lang/rust/pull/56351 добавил -C linker-flavor .

Непонятно, для чего предназначена эта проблема. Похоже, что было бы лучше закрыть это, чтобы иметь определенные проблемы, например, «Связать с LLD для целей -msvc, когда инструментальная цепочка Microsoft недоступна».

Для меня эта проблема связана с включением LLD в качестве компоновщика по умолчанию для всех целей. Я бы хотел этого, потому что LLD работает очень быстро, а время компоновки часто является важным компонентом времени компиляции, а скорость компиляции является постоянной проблемой.

FWIW Я зарегистрировал ошибку для поддержки LLD в macOS, а не в BMO. Видимо это WONTFIX. Из комментариев там кажется, что это не так просто, как «LLD чрезвычайно быстр», поскольку LLD на разных платформах - это разные программы, а один на macOS сломан из-за застопорившейся разработки.

Согласился с @briansmith, что было бы хорошо иметь специальные задачи для отслеживания статуса этого для разных целей, хотя вместо того, чтобы закрывать это, мы могли бы затем превратить это в метабуг. Если есть кто-нибудь, кто знает больше о том, для каких целей стоит открывать вопросы, пожалуйста, не стесняйтесь, так как я очень не в курсе о статусе поддержки LLD.

Связь с LLD где-нибудь задокументирована? У меня (в Linux) rustc -C linker-flavor=ld.lld hello.rs , но мне не повезло. Я думал, что LLD распространяется с нашей копией LLVM, я ошибаюсь? Я также пробовал установить LLD через apt, но rustc все еще озадачен. Какие шаги необходимо предпринять, чтобы сегодня опробовать LLD с кодом Rust?

@bstrie Вы должны дополнительно передать аргумент -C linker=rust-lld .

Предполагается, что он будет работать с грузом? В настоящее время я получаю следующие ошибки при попытке создать пустой проект на последней ночной сборке ржавчины и груза.

$ RUSTFLAGS='-C linker=rust-lld' cargo build
   Compiling rust3 v0.1.0 (/home/carado/tmp/rust3)
error: linking with `rust-lld` failed: exit code: 1
  |
  = note: "rust-lld" "-flavor" "gnu" "-L" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/home/carado/tmp/rust3/target/debug/deps/rust3-c4f8c40972021c55.2ualxzb8lqn4ho3y.rcgu.o" "/home/carado/tmp/rust3/target/debug/deps/rust3-c4f8c40972021c55.32vfyq64cfbzv618.rcgu.o" "/home/carado/tmp/rust3/target/debug/deps/rust3-c4f8c40972021c55.4rbt3m5y8o8cl09t.rcgu.o" "/home/carado/tmp/rust3/target/debug/deps/rust3-c4f8c40972021c55.ben0932xzwyt64v.rcgu.o" "/home/carado/tmp/rust3/target/debug/deps/rust3-c4f8c40972021c55.fzsdnygvstiwzxo.rcgu.o" "/home/carado/tmp/rust3/target/debug/deps/rust3-c4f8c40972021c55.x0rq6ifodcf11zi.rcgu.o" "-o" "/home/carado/tmp/rust3/target/debug/deps/rust3-c4f8c40972021c55" "/home/carado/tmp/rust3/target/debug/deps/rust3-c4f8c40972021c55.1m259ox4uzrzk583.rcgu.o" "--gc-sections" "-pie" "-zrelro" "-znow" "-L" "/home/carado/tmp/rust3/target/debug/deps" "-L" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "--start-group" "-Bstatic" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-44988553032616b2.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-607feef6be9150b2.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libbacktrace-a8dbf6d92401e34a.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libbacktrace_sys-9a4716f5e8a3e722.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-988a64d96b043c6d.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-cadd6177b8c6d586.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-8f1d8efc92b45369.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-1e76014677816767.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-cc28bce38cb195d9.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-4123e9e89add689a.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-4d259c17788c1fb5.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-9495dbda85bb8f16.rlib" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-793d0026c575805f.rlib" "--end-group" "/home/carado/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-33c3162edae6574e.rlib" "-Bdynamic" "-ldl" "-lrt" "-lpthread" "-lgcc_s" "-lc" "-lm" "-lrt" "-lpthread" "-lutil" "-lutil"
  = note: rust-lld: error: unable to find library -ldl
          rust-lld: error: unable to find library -lrt
          rust-lld: error: unable to find library -lpthread
          rust-lld: error: unable to find library -lgcc_s
          rust-lld: error: unable to find library -lc
          rust-lld: error: unable to find library -lm
          rust-lld: error: unable to find library -lrt
          rust-lld: error: unable to find library -lpthread
          rust-lld: error: unable to find library -lutil
          rust-lld: error: unable to find library -lutil


error: aborting due to previous error

error: Could not compile `rust3`.

To learn more, run the command again with --verbose.

Я получаю те же ошибки, что и Карадо. Удалось "вставить" -L / usr / lib в вызов компоновщика, но это просто сокращает список пропущенных библиотек до -lgcc которого нет нигде в системе, как libgcc (там libgcc_s.a ) Я подозреваю, что это результат какого-то гнуизма, но не могу понять, как это исправить.

@almindor попробуйте RUSTFLAGS='-C linker=rust-lld -L /usr/lib -L /usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0' или что-то подобное. Путь будет зависеть от вашего дистрибутива и версии компилятора.

Мой комментарий выше - правильный способ использования LLD? Я не могу заставить его работать, так как каждая программа вылетает с SIGSEGV :

Reading symbols from target/debug/hello...
(gdb) show directories
Source directories searched: ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/etc:$cdir:$cwd
(gdb) r
Starting program: target/debug/hello 

Program received signal SIGSEGV, Segmentation fault.
core::ops::function::FnOnce::call_once{{vtable-shim}} () at /rustc/a7f28678bbf4e16893bb6a718e427504167a9494/src/libcore/ops/function.rs:231
(gdb) l
226     #[stable(feature = "fn_once_output", since = "1.12.0")]
227     type Output;
228 
229     /// Performs the call operation.
230     #[unstable(feature = "fn_traits", issue = "29625")]
231     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
232 }
233 
234 mod impls {
235     #[stable(feature = "rust1", since = "1.0.0")] 
(gdb) info reg
rax            0x0                 0
rbx            0x0                 0
rcx            0x0                 0
rdx            0x0                 0
rsi            0x0                 0
rdi            0x0                 0
rbp            0x0                 0x0
rsp            0x7fffffffddb0      0x7fffffffddb0
r8             0x0                 0
r9             0x0                 0
r10            0x0                 0
r11            0x0                 0
r12            0x0                 0
r13            0x0                 0
r14            0x0                 0
r15            0x0                 0
rip            0x7ffff7ffc000      0x7ffff7ffc000 <core::ops::function::FnOnce::call_once{{vtable-shim}}>
eflags         0x10202             [ IF RF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
(gdb) disassemble 
Dump of assembler code for function core::ops::function::FnOnce::call_once{{vtable-shim}}:
=> 0x00007ffff7ffc000 <+0>: mov    (%rdi),%rax
   0x00007ffff7ffc003 <+3>: mov    (%rax),%rdi
   0x00007ffff7ffc006 <+6>: jmpq   *0x11d4(%rip)        # 0x7ffff7ffd1e0
End of assembler dump.

Для всех, кто попадает сюда, магическое заклинание - RUSTFLAGS="-C link-arg=-fuse-ld=lld" cargo build если у вас GCC 9 или Clang в качестве компилятора. В качестве альтернативы -C linker=clang должен работать независимо от версии GCC, поэтому может быть предпочтительнее.

Чтобы сделать это постоянным, вы можете добавить его в ~/.cargo/config или .cargo/config в конкретном проекте:

[build]
rustflags = ["-C", "linker=clang"]
# rustflags = ["-C", "link-arg=-fuse-ld=lld"]

@lnicola обратите внимание, что он работает только при использовании GCC 9 или Clang в качестве CC.

@bstrie , знаете ли вы, в каком состоянии это сейчас? Что мешает продвинуться с этим?

@ mati865 знаете ли вы альтернативный вызов для людей со старым GCC?

@lnicola на всех моих платформах есть Clang + GCC 9, и я не исследовал, как его использовать с несовместимыми компиляторами.

@jonhoo Я не в курсе всех работ в этой области, полагаю, вы захотите спросить команду компиляторов.

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

Сортировка; @ rust-lang / compiler кто-нибудь знает, каков текущий статус этой проблемы?

Для тех, кому удалось заставить LLD работать с Rust, не могли бы вы дополнительно включить подробную информацию о своей платформе и конкретных версиях всех используемых компиляторов? Я до сих пор вижу, как у людей в дикой природе возникают проблемы с тем, чтобы заставить его работать, даже при соблюдении перечисленных здесь советов.

Команда, которую я опубликовал выше, работает в Linux с GCC 9.2.0 и LLD 9.0.0. Я думаю, что иногда это работает и в Windows, но я видел кого-то с GCC 9 для Windows, который не поддерживал -fuse = lld. На MacOS пробовать не стоит, судя по некоторым ссылкам, размещенным здесь.

Для тех, кому удалось заставить LLD работать с Rust, не могли бы вы дополнительно включить подробную информацию о своей платформе и конкретных версиях всех используемых компиляторов? Я до сих пор вижу, как у людей в дикой природе возникают проблемы с тем, чтобы заставить его работать, даже при соблюдении перечисленных здесь советов.

кошка / и т. д. / системный выпуск
Выпуск 30 Fedora (Тридцать)

cc --version
cc (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)

ld.lld --version
LLD 8.0.0 (совместим с линкерами GNU)

Надеюсь, это поможет

но я видел кого-то с GCC 9 для Windows, который не поддерживал -fuse = lld

@lnicola
Сборки Windows GCC 9 поддерживают -fuse-ld=lld (если только они не пропатчены, чтобы не поддерживать его, но зачем кому-то это делать?).
Я полагаю, что компонент rust-mingw был установлен и компоновщик не был переопределен в .cargo/config . Таким образом, rustc выбрал поставляемый GCC 6 вместо системного.

Другая проблема в Windows - это жестко запрограммированный флаг компоновщика --enable-long-section-names который LLD 9 и старше не поддерживает (в будущем планируется его поддержка). Чтобы обойти это, вы можете:

  • создать оболочку, которая удаляет этот флаг
  • патч LLD, чтобы принять этот флаг как запретный
  • используйте локальные исправленные сборки Rust, которые не используют этот флаг

Другая проблема в Windows - это жестко запрограммированный флаг компоновщика --enable-long-section-names, который LLD 9 и старше не поддерживает (в будущем планируется его поддержка).

Эта часть исправлена: https://github.com/rust-lang/rust/pull/66257
Пользователям Windows-GNU по-прежнему приходится выполнять ручную работу, чтобы использовать компилятор C, который поддерживает -fuse-ld=lld .

@bstrie : это работает со стабильным и https://github.com/rust-gamedev/wg/issues/50

Еще одна точка данных: при использовании RUSTFLAGS="-C link-arg=-fuse-ld=lld" при сборке самого rustc время компоновки падает с 93 до 41 на моем быстром 14-ядерном Linux.

@nnethercote : Это отличается от установки linker=lld (например) в разделе [target.x86_64-unknown-linux-gnu] раздела config.toml ?

@ Aaron1011 : Я предполагаю, что оба подхода будут иметь одинаковый эффект, но я сам это не проверял.

@ Aaron1011 он должен Https://github.com/rust-lang/rust/issues/39915#issuecomment -538049306.

@ mati865
Вы пробовали построить rustc на x86_64-pc-windows-gnu с LLD в качестве компоновщика?

Я попробовал это сегодня, и LLD либо зависает в середине сборки и перестает выполнять какую-либо работу, либо жалуется на unknown argument: --version-script=... .
Зависание также происходит, если LLD используется только для связывания LLVM с

[llvm]
use-linker = "lld"

Версии инструмента:

$ ld.lld --version
LLD 9.0.1 (https://github.com/msys2/MINGW-packages.git 5e3b8820ed9f04221affee4197e458aca2612e87) (compatible with GNU linkers)

$ gcc --version
gcc.exe (Rev2, Built by MSYS2 project) 9.2.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

@petrochenkov да, я мог бы построить это с помощью некоторых хаков:

  • Бэкэнд LLD COFF не поддерживает сценарии компоновщика, но и LD, и LLD подходят для файлов в стиле MSVC. .def files; легко решить
  • LLD ожидает, что библиотеки будут начинаться с lib (это стандарт в мире UNIX), но каким-то образом Rust закончил тем, что не сделал этого для всех целей windows-* : https://github.com/rust-lang/ ржавчина / blob / 9ebf47851a357faa4cd97f4b1dc7835f6376e639 / src / libstd / sys / windows / env.rs # L4
    LD не возражает в любом случае, и я не знаю, стоит ли нажимать на LLD или на Rust, чтобы исправить это.

Я записываю здесь некоторые будущие возможности. Хотя необходимы некоторые усилия по реализации, я думаю, что они помогут решить некоторые давние болевые точки в разработке Rust:

  • Вместо использования внешнего lld создайте и используйте его как статические библиотеки в rustc. Это обеспечивает более тесную интеграцию с самим rustc, улучшает готовность к работе и открывает возможности в будущем.
  • Вместо передачи большого количества имен путей в lld в качестве команды компоновщика используйте виртуальную файловую систему и передавайте эти данные из памяти в память вместо использования дискового ввода-вывода всякий раз, когда для этого достаточно места в памяти. Для более крупных проектов это может сэкономить сотни или даже тысячи мегабайт дискового ввода-вывода и, таким образом, сократить время компиляции.

Вместо передачи большого количества имен путей в lld в качестве команды компоновщика используйте виртуальную файловую систему и передавайте эти данные из памяти в память вместо использования дискового ввода-вывода всякий раз, когда для этого достаточно места в памяти. Для более крупных проектов это может сэкономить сотни или даже тысячи мегабайт дискового ввода-вывода и, таким образом, сократить время компиляции.

Дело не только в пропускной способности ввода-вывода. На таких платформах, как Windows, особенно когда включен Защитник Windows, каждый файл, с которым вы хотите работать, добавляет довольно значительную потерю времени, а модель модуля кодогенерации Rust означает, что ящики разбиты на сотни крошечных объектных файлов, которые могут быстро собрать большой объем компиляции. время.

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

Что такое lld

Компоновщик, являющийся частью проекта llvm, что желательно по двум причинам:

  • это очень удобно для кросс-компиляции (отсюда и упор на встроенные цели)
  • это очень быстро (часто выполняется вдвое быстрее, чем Gold - связывание может занять несколько минут для больших проектов (rustc, servo и т. Большое дело.)

Что Rust делает с lld сегодня

  • В настоящее время Rust поставляет свою собственную копию lld на большинстве платформ в виде двоичного файла, который он называет rust-lld.
  • rust-lld используется по умолчанию для многих целей без операционной системы
  • rust-lld используется по умолчанию для wasm
  • (?) вы можете явно запросить использование rust-lld с помощью "-C linker-flavour" (неясно, что именно это делает на платформах, отличных от голого металла, см. ниже)

Проблемы с использованием rust-lld в других местах (например, настольный linux / mac / windows)

  • Бэкэнд macOS (Mach-O) для lld сломан и заброшен

    • началось переписывание с нуля, но это только начало

  • На платформах linux / unix вы не должны напрямую вызывать ld / lld. Вы должны вызвать компоновщик через системный компилятор c (т.е. gcc), в обязанности которого входит обнаружение системных символов, таких как crt1.o, и их передача ld. Это означает, что мы не можем «просто» использовать rust-lld; мы должны передать его в gcc / clang / something. (мы не хотим сами реализовывать эту системную символьную логику)

    • Как правило, вы не можете указать компоновщик в качестве пути, вы должны вставить его в путь поиска компилятора C как "ld"

    • В качестве альтернативы вы можете сделать то же самое, но ввести его как «ld.lld» и передать «-fuse-ld = lld»



      • Это может быть важно, очевидно, lld выполняет определение двоичного имени в стиле clang, если оно выполняется как «ld» или «ld.lld» (требуется исследование)


      • К сожалению, -fuse-ld = lld является только частью GCC 9, поэтому нам может потребоваться определение функции / версии для его использования (у clang это уже давно)



  • windows-msvc, по- видимому, в хорошей форме и, похоже, имеет некоторую ограниченную поддержку использования rust-lld в бэкэнде, но я не понимаю, что здесь нужно сделать.
  • windows-mingw, похоже, находится примерно в том же месте, что и linux / unix, за исключением того, что вы можете получить древний GCC, и все немного шатко, потому что псевдо-windows-linux не совсем хорошо протестированная конфигурация?

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

Я написал две метабуга для целенаправленных усилий по использованию (rust-) lld по умолчанию на двух платформах:

  • # 71515 - x64 Ubuntu 20.04 LTS (и в более широком смысле все платформы x64 ELF)
  • # 71520 - окна x64 msvc

windows-msvc, по-видимому, в хорошей форме и, похоже, имеет некоторую ограниченную поддержку использования rust-lld в бэкэнде, но я не понимаю, что здесь нужно сделать.

LLD + windows-msvc находится в довольно хорошем состоянии, в настоящее время я использую эту установку для разработки rustc .

Вся необходимая поддержка lld-link есть в бэкэнде rustc , но есть ошибки вроде https://github.com/rust-lang/rust/issues/68647.

  • Это может быть важно, очевидно, lld выполняет определение двоичного имени в стиле clang, если оно выполняется как «ld» или «ld.lld» (требуется исследование)

это так, но ld и ld.lld - это один и тот же режим: https://github.com/rust-lang/llvm-project/blob/rustc/10.0-2020-02-05/lld/tools/lld/lld. cpp (то же самое с 8.0-2019-01-16)

  • К сожалению, -fuse-ld = lld является только частью GCC 9, поэтому нам может потребоваться определение функции / версии для его использования (у clang это уже давно)

поскольку ld.lld совпадает с ld, и согласно https://patches-gcc.linaro.org/patch/11148/ единственное изменение с -fuse-ld = lld - запускать ld.lld вместо ld, если мы используем инъекцию PATH, все должно быть в порядке. Я думаю, что блокировать это для gcc 9+ нехорошо: в debian stable только 8.3, а яблочко, вероятно, не будет выпущено до 2021 года.

  • windows-mingw, похоже, находится примерно в том же месте, что и linux / unix, за исключением того, что вы можете получить древний GCC, и все немного шатко, потому что псевдо-windows-linux не совсем хорошо протестированная конфигурация?

mingw-w64 6.0.0, выпущенный 16 сентября 2018 г., имеет gcc 8.3.0, в котором нет -fuse-ld = lld, но он все еще достаточно новый. mingw-w64 7.0.0, выпущенный 11.11.2019, имеет gcc 9.3.0, у которого есть -fuse-ld = lld. Debian buster (стабильный) имеет 6.0.0, яблочко (тестирование) - 7.0.0. Debian stretch (oldstable) имеет только 5.0.1 с gcc 6.3.0, но я думаю, что было бы разумно потребовать последнюю версию debian stable для поддержки lld, если есть существенные проблемы с gcc 6.3.

Я написал две метабуга для целенаправленных усилий по использованию (rust-) lld по умолчанию на двух платформах:

  • # 71515 - x64 Ubuntu 20.04 LTS (и в более широком смысле все платформы x64 ELF)
  • # 71520 - окна x64 msvc

О порте lld для macOS (Mach-O): похоже, он работает или, по крайней мере, находится в значительно лучшей форме, поскольку https://github.com/rust-lang/rust/issues/39915#issuecomment -618726211 было написано!

Используя этот коммит LLVM , я построил lld и установил его в качестве компоновщика для конкретного проекта для tokio-rs / tracing . Затем я построил трассировку для nightly-x86_64-apple-darwin и успешно выполнил все тесты. Мне особенно нравится время сборки (отладки):

  • С ld чистая cargo build заняла 35 секунд.
  • С lld чистая cargo build заняла 20 секунд.

Обратите внимание, что:

@davidbarsky Круто! Из любопытства, как эта производительность сравнивается с zld ? (https://github.com/michaeleisel/zld)

Кроме того, вы учли термики? MBP очень быстро подвергаются термическому регулированию, особенно с профилем скорости вентилятора по умолчанию. Просто подождите, пока нижняя часть тренажера рядом с шарниром остынет на ощупь, перед пробежкой должно помочь добиться однородности.

У меня как раз такой баг, на Ubuntu 16 i686

Была ли эта страница полезной?
0 / 5 - 0 рейтинги