Add support for static linking of `sqlx`

`sqlx` requires linking against OpenSSL twice:

- `sqlx-macros` needs to link against OpenSSL as a shared libary for use
  at compile time.
- `sqlx` needs to link against OpenSSL a static library for use at
  runtime.

You can find the details here:

https://github.com/launchbadge/sqlx/issues/670
https://github.com/sfackler/rust-openssl/issues/1337

We go with the fix proposed by @sfackler, and add a test program that we
can use to verify everything works correctly.

We remove a few `OPENSSL`-related variables that were added 4 years ago,
and that no longer appear to be needed.
This commit is contained in:
Eric Kidd 2020-09-03 16:18:59 -04:00
parent 9f6efa542f
commit 727d912b3b
13 changed files with 1386 additions and 11 deletions

View File

@ -67,7 +67,7 @@ RUN apt-get update && \
curl -fLO https://github.com/EmbarkStudios/cargo-deny/releases/download/$CARGO_DENY_VERSION/cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz && \
tar xf cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz && \
mv cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl/cargo-deny /usr/local/bin/ && \
rm -rf cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz
rm -rf cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl cargo-deny-$CARGO_DENY_VERSION-x86_64-unknown-linux-musl.tar.gz
# Static linking for C++ code
RUN sudo ln -s "/usr/bin/g++" "/usr/bin/musl-g++"
@ -142,11 +142,8 @@ RUN echo "Building libpq" && \
cd ../../bin/pg_config && make && sudo make install && \
rm -r /tmp/*
ENV OPENSSL_DIR=/usr/local/musl/ \
OPENSSL_INCLUDE_DIR=/usr/local/musl/include/ \
DEP_OPENSSL_INCLUDE=/usr/local/musl/include/ \
OPENSSL_LIB_DIR=/usr/local/musl/lib/ \
OPENSSL_STATIC=1 \
ENV X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR=/usr/local/musl/ \
X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_STATIC=1 \
PQ_LIB_STATIC_X86_64_UNKNOWN_LINUX_MUSL=1 \
PG_CONFIG_X86_64_UNKNOWN_LINUX_GNU=/usr/bin/pg_config \
PKG_CONFIG_ALLOW_CROSS=true \

View File

@ -2,6 +2,8 @@
[![Docker Image](https://img.shields.io/docker/pulls/ekidd/rust-musl-builder.svg?maxAge=2592000)](https://hub.docker.com/r/ekidd/rust-musl-builder/)
[Source on GitHub](https://github.com/emk/rust-musl-builder)
## What is this?
Do you want to compile a completely static Rust binary with no external dependencies? If so, try:
@ -13,7 +15,7 @@ rust-musl-builder cargo build --release
This command assumes that `$(pwd)` is readable and writable by uid 1000, gid 1000. At the moment, it doesn't attempt to cache libraries between builds, so this is best reserved for making final release builds.
For a more realistic example, see the `Dockerfile` for [examples/using-diesel](./examples/using-diesel).
For a more realistic example, see the `Dockerfile` for [examples/using-diesel](./examples/using-diesel) [examples/using-sqlx](./examples/using-sqlx).
## Deploying your Rust application
@ -36,7 +38,7 @@ In general, we provide the following tagged Docker images:
Rust, please file an issue.
At a minimum, each of these images should be able to
compile [examples/using-diesel](./examples/using-diesel).
compile [examples/using-diesel](./examples/using-diesel) and [examples/using-sqlx](./examples/using-sqlx).
[comp]: https://rust-lang.github.io/rustup-components-history/index.html
@ -94,8 +96,6 @@ This image also supports the following extra goodies:
If your application uses OpenSSL, you will also need to take a few extra steps to make sure that it can find OpenSSL's list of trusted certificates, which is stored in different locations on different Linux distributions. You can do this using [`openssl-probe`](https://crates.io/crates/openssl-probe) as follows:
```rust
extern crate openssl_probe;
fn main() {
openssl_probe::init_ssl_cert_env_vars();
//... your code

View File

@ -9,3 +9,4 @@ diesel = { version = "1", features = ["postgres", "sqlite"] }
libsqlite3-sys = { version = "*", features = ["bundled"] }
# Needed for Postgres.
openssl = "*"
openssl-probe = "0.1.2"

View File

@ -46,6 +46,8 @@ where
}
fn main() {
openssl_probe::init_ssl_cert_env_vars();
println!("Hello, world!");
// Only run our database example if we have a database. Otherwise, we just

View File

@ -0,0 +1 @@
target

1265
examples/using-sqlx/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
[package]
name = "using-sqlx"
version = "0.1.0"
authors = ["Eric Kidd <git@randomhacks.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
openssl-probe = "0.1.2"
sqlx = { version = "0.4.0-beta.1", default-features = false, features = ["runtime-tokio", "macros", "offline", "postgres"] }
tokio = { version = "0.2", features = ["macros"] }

View File

@ -0,0 +1,25 @@
# -*- mode: dockerfile -*-
#
# An example Dockerfile showing how to build a Rust executable using this
# image, and deploy it with a tiny Alpine Linux container.
# You can override this `--build-arg BASE_IMAGE=...` to use different
# version of Rust or OpenSSL.
ARG BASE_IMAGE=ekidd/rust-musl-builder:latest
# Our first FROM statement declares the build environment.
FROM ${BASE_IMAGE} AS builder
# Add our source code.
ADD --chown=rust:rust . ./
# Build our application.
RUN cargo build --release
# Now, we need to build our _real_ Docker container, copying in `using-sqlx`.
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder \
/home/rust/src/target/x86_64-unknown-linux-musl/release/using-sqlx \
/usr/local/bin/
CMD /usr/local/bin/using-sqlx

View File

@ -0,0 +1,12 @@
version: "2.0"
services:
app:
build: .
volumes:
- cargo:/home/rust/.cargo
- target:/home/rust/src/target
volumes:
cargo: {}
target: {}

View File

@ -0,0 +1,23 @@
{
"db": "PostgreSQL",
"bf54a84704792059fc3a494889dce274bb09f5cadc8c7be61a9b85abbceb001f": {
"query": "SELECT $1::INTEGER AS value",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "value",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Int4"
]
},
"nullable": [
null
]
}
}
}

View File

@ -0,0 +1,23 @@
use std::env;
use sqlx::{Connection, postgres::PgConnection};
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
openssl_probe::init_ssl_cert_env_vars();
let url = env::var("POSTGRES_URL")
.unwrap_or_else(|_| "postgresql://postgres@localhost/postgres".to_owned());
// Create a connection.
let mut conn = PgConnection::connect(&url).await?;
// Make a simple query using the `query!` macro.
let row = sqlx::query!("SELECT $1::INTEGER AS value", 2i32)
.fetch_one(&mut conn)
.await?;
assert_eq!(row.value, Some(2));
Ok(())
}

View File

@ -4,7 +4,7 @@
set -euo pipefail
# Make sure we can build some of our more important test images.
for EXAMPLE in using-diesel; do
for EXAMPLE in using-diesel using-sqlx; do
docker build \
--build-arg BASE_IMAGE="$IMAGE_NAME" \
-t rust-musl-builder-"$EXAMPLE" \

View File

@ -41,6 +41,20 @@ fi
echo -e '[PASS] ARMhf binary is statically linked.\n'
"
# Make sure we can build a static executable using `sqlx`.
docker build -t rust-musl-builder-using-sqlx examples/using-sqlx
docker run --rm rust-musl-builder-using-sqlx sh -c "
set -euo pipefail
echo -e '--- Test case for sqlx:'
echo 'ldd says:'
if ldd /usr/local/bin/using-sqlx; then
echo '[FAIL] Executable is not static!' 1>&2
exit 1
fi
echo -e '[PASS] using-sqlx binary is statically linked.\n'
"
# Make sure we can build a static executable using `git2`.
docker build -t rust-musl-builder-linking-with-git2 examples/linking-with-git2
docker run --rm rust-musl-builder-linking-with-git2 bash -c "