Как скомпилировать статический мусорный бинарник проекта Rust с нативными зависимостями?

У меня есть проект с зависимостями от Hyper и Diesel, и из-за этого, на нативных библиотеках OpenSSL и libpq. Проект основан на ночных Rust, потому что он использует плагины компилятора.

Моя текущая попытка - построить контейнер Docker. У меня есть MUSL libc и библиотеки makeи установить с префиксом /usr/local/musl, я бегу cargo с помощью следующей команды: (Не уверен, что некоторые опции избыточны, я не слишком разбираюсь в цепочке компиляторов и даже не уверен, что они заканчиваются компоновщиком, но я должен попробовать, верно.)

LDFLAGS="-static -L/usr/local/musl/lib" \
LD_LIBRARY_PATH=/usr/local/musl/lib:$LD_LIBRARY_PATH \
CFLAGS="-I/usr/local/musl/include" \
PKG_CONFIG_PATH=/usr/local/musl/lib/pkgconfig \
cargo build --release --target=x86_64-unknown-linux-musl

Когда я ldd Полученный файл, это показывает это:

$ ldd server
linux-vdso.so.1 (0x00007fffb878e000)
libpq.so.5 => /usr/local/musl/lib/libpq.so.5 (0x00007f4d730e7000)
libssl.so.1.0.0 => /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0 (0x00007f4d72e82000)
libcrypto.so.1.0.0 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0 (0x00007f4d72a85000)
libc.so => /usr/local/musl/lib/libc.so (0x00007f4d727f6000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f4d725f2000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4d72246000)
/lib/ld64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x000055e2124a2000)

Там все это динамически связанные вещи, а некоторые даже с цепочкой "x86_64-linux-gnu"! Что пошло не так?

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

Когда я использовал --verbose с грузом я получил следующее rustc команда, которая на самом деле создает исполняемый файл: http://pastebin.com/ywv0zNBK (упс outdir а также -Z print-link-args, добавил я) Добавление print-link-args флаг, я получил следующую команду компоновщика: http://pastebin.com/Aw43qd7h

Как я могу получить cargo или же rustc верить, что я хочу статический бинарный файл?

3 ответа

Решение

Проблема заключалась в том, что для каждого ящика, обеспечивающего собственную зависимость, скажем, OpenSSL, существует build.rs скрипт сборки, который отвечает за передачу параметров сборки и связывания с Cargo и rustc, (Например: они распечатывают что-то вроде cargo:rustc-link-lib=static=ssl какой груз тогда читает и действует соответственно.)

Таким образом, установка "стандартных" переменных среды GCC вряд ли будет иметь какой-либо эффект. Вы должны проверить каждый build.rs отдельно, чтобы знать, как заставить этот конкретный ящик перевозить груз, это варианты. Для OpenSSL это env vars вроде OPENSSL_DIR, OPENSSL_STATIC и т.п.

Еще одно препятствие заключается в том, что если вы используете плагины компилятора, они также могут быть скомпилированы с целевым триплетом (по крайней мере, docker_codegen). С другой стороны, они динамически связаны в процессе компиляции. Это означает, что не только статические библиотеки должны быть правильно связаны, вы также должны иметь динамические библиотеки целевого разнообразия, такие как MUSL libc.so на месте и правильно установлен (LD_LIBRARY_PATH так далее.).

Я сделал тщательно прокомментированный Dockerfile, который статически строит мой проект с некоторыми нативными зависимостями. Это может помочь и другим.

https://github.com/golddranks/rust_musl_docker/blob/master/Dockerfile.template

Если вы хотите статически связать программу Rust без собственных зависимостей, это намного проще:

$ rustup target add x86_64-unknown-linux-musl
$ cargo build --release --target=x86_64-unknown-linux-musl

У меня была такая же проблема с ldd и GCC. Цель musl была создана в другом каталоге; не в target/release/... но в target/x86_64-unknown-linux-musl/release/....

Другие вопросы по тегам