Как скомпилировать статический мусорный бинарник проекта 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/...
.