fix(compilation): use cross for statically linking against musl

pull/36/head
Maxim De Clercq 2021-09-08 15:53:48 +02:00
parent 3d024db2e9
commit 490dfcf2f2
No known key found for this signature in database
GPG Key ID: D35643779C52BA70
11 changed files with 115 additions and 169 deletions

View File

@ -9,5 +9,6 @@
!src !src
!tests !tests
!web !web
!target/x86_64-unknown-linux-musl/release/rbd
web/node_modules web/node_modules

2
Cargo.lock generated
View File

@ -939,6 +939,7 @@ version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda" checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda"
dependencies = [ dependencies = [
"pkg-config",
"vcpkg", "vcpkg",
] ]
@ -1221,6 +1222,7 @@ dependencies = [
"jwt", "jwt",
"mimalloc", "mimalloc",
"openssl", "openssl",
"pq-sys",
"rand", "rand",
"rocket", "rocket",
"rocket_sync_db_pools", "rocket_sync_db_pools",

View File

@ -21,7 +21,7 @@ serde = { version = "1.0.127", features = [ "derive" ] }
diesel = { version = "1.4.7", features = ["postgres", "uuidv07", "chrono"] } diesel = { version = "1.4.7", features = ["postgres", "uuidv07", "chrono"] }
diesel_migrations = "1.4.0" diesel_migrations = "1.4.0"
# To properly compile libpq statically # To properly compile libpq statically
openssl = "0.10.36" openssl = "*"
# For password hashing & verification # For password hashing & verification
rust-argon2 = "0.8.3" rust-argon2 = "0.8.3"
rand = "0.8.4" rand = "0.8.4"
@ -38,6 +38,11 @@ base64 = "0.13.0"
figment = { version = "*", features = [ "yaml" ] } figment = { version = "*", features = [ "yaml" ] }
mimalloc = { version = "0.1.26", default_features = false } mimalloc = { version = "0.1.26", default_features = false }
[dependencies.pq-sys]
version = "*"
default-features = false
features = ["pkg-config"]
[profile.release] [profile.release]
lto = "fat" lto = "fat"
panic = "abort" panic = "abort"

3
Cross.toml 100644
View File

@ -0,0 +1,3 @@
[target.x86_64-unknown-linux-musl]
image = "rusty-builder:x86_64-unknown-linux"

View File

@ -1,19 +1,4 @@
FROM rust:1.54 FROM scratch
ENV PREFIX="/usr/src/out/prefix" \ COPY target/x86_64-unknown-linux-musl/release/rbd /
CC="musl-gcc -fPIC -pie -static" \ RUN ["/rbd"]
LD_LIBRARY_PATH="$PREFIX" \
PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" \
PATH="/usr/local/bin:/root/.cargo/bin:$PATH"
RUN apt update && \
apt install -y --no-install-recommends \
musl-dev \
musl-tools \
libpq-dev \
libssl-dev && \
rustup target add x86_64-unknown-linux-musl && \
mkdir "$PREFIX" && \
echo "$PREFIX/lib" >> /etc/ld-musl-x86_64.path
WORKDIR /usr/src/app

68
Dockerfile.build 100644
View File

@ -0,0 +1,68 @@
# Cross-compile for a specific target triplet (x86_64 by default)
ARG TARGET
ARG CORES=4
FROM rustembedded/cross:${TARGET}-musl
# Create download directory
RUN mkdir /src
### Environment
# Configure compiler
ENV MAKE="make -j$CORES" \
CC="musl-gcc -fPIE -pie -static" \
PREFIX=/usr/local/x86_64-linux-musl \
RUSTFLAGS="-C relocation-model=static"
# Configure paths
ENV PATH=$PREFIX/bin:$PATH \
C_INCLUDE_PATH=$PREFIX/include \
LD_LIBRARY_PATH=$PREFIX/lib
# Configure pkg-config
ENV PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig \
PKG_CONFIG_ALLOW_CROSS=true \
PKG_CONFIG_ALL_STATIC=true
# Install development libraries
RUN apt-get update && apt-get install -y \
bison \
flex \
musl-dev \
musl-tools
### OpenSSL
ARG SSL_VER
# Download OpenSSL
RUN curl -sSL "https://www.openssl.org/source/openssl-${SSL_VER}.tar.gz" | tar -xzC /src
# Build OpenSSL statically
RUN cd "/src/openssl-${SSL_VER}" \
&& ./Configure \
no-shared \
no-zlib \
-fPIC \
--prefix=$PREFIX \
--openssldir=$PREFIX/ssl \
linux-x86_64 \
&& $MAKE depend \
&& $MAKE \
&& $MAKE install
# Configure OpenSSL crate
ENV OPENSSL_STATIC=true \
OPENSSL_NO_VENDOR=true
### PostgreSQL
ARG PQ_VER
# Download PostgreSQL
RUN curl -sSL "https://ftp.postgresql.org/pub/source/v${PQ_VER}/postgresql-${PQ_VER}.tar.gz" | tar -xzC /src
# Build PostgreSQL statically
RUN cd "/src/postgresql-${PQ_VER}" \
&& CPPFLAGS=-I$PREFIX/include LDFLAGS="-L$PREFIX/lib" \
./configure \
--with-openssl \
--without-readline \
--without-zlib \
--prefix=$PREFIX \
--host=$TARGET \
&& ${MAKE} -C src/interfaces/libpq all-static-lib \
&& ${MAKE} -C src/interfaces/libpq install-lib-pc \
&& ${MAKE} -C src/interfaces/libpq install-lib-static \
&& ${MAKE} -C src/bin/pg_config \
&& ${MAKE} -C src/bin/pg_config install

137
Makefile
View File

@ -6,133 +6,36 @@ SSL_VER ?= 1.1.1k
# Dumb-init version # Dumb-init version
DI_VER ?= 1.2.5 DI_VER ?= 1.2.5
# Compilation target triplet
# =====AUTO-GENERATED VARIABLES===== # Supported targets: https://github.com/rust-embedded/cross#supported-targets
# This is such a lovely oneliner TARGET = x86_64-unknown-linux
# NOTE: $(dir PATH) outputs a trailing slash
OUT_DIR ?= $(dir $(abspath $(lastword $(MAKEFILE_LIST))))out
PREFIX := $(OUT_DIR)/prefix
OPENSSL_DIR := $(OUT_DIR)/openssl-$(SSL_VER)
PQ_DIR := $(OUT_DIR)/postgresql-$(PQ_VER)
DI_DIR := $(OUT_DIR)/dumb-init-$(DI_VER)
# Used in various make calls to specify parallel recipes
CORES != nproc CORES != nproc
# =====ENVIRONMENT VARIABLES=====
export CC := musl-gcc -fPIC -pie -static
export LD_LIBRARY_PATH := $(PREFIX)
export PKG_CONFIG_PATH := /usr/local/lib/pkgconfig
export PATH := /usr/local/bin:/root/.cargo/bin:$(PATH)
# TODO check for header files (openssl-dev, libpq-dev) both for Arch & Ubuntu
# Create the out dir
$(shell mkdir -p "$(PREFIX)")
# =====BUILDING THE STATIC BINARY=====
.PHONY: all .PHONY: all
all: build all: build-debug
.PHONY: builder .PHONY: builder
builder: builder:
docker build \ docker build \
-t rusty-builder:latest - < docker/Dockerfile.builder --build-arg TARGET=$(TARGET) \
--build-arg CORES=$(CORES) \
--build-arg SSL_VER=$(SSL_VER) \
--build-arg PQ_VER=$(PQ_VER) \
--tag rusty-builder:$(TARGET) \
--file Dockerfile.build \
.
.PHONY: docker .PHONY: build-debug
docker: builder build-debug: builder
docker run \ cross build --target "$(TARGET)-musl"
--rm \
-v "$$PWD:/usr/src" \
--workdir "/usr/src" \
-it \
rusty-builder:latest \
bash build.sh
.PHONY: run
run: builder
docker-compose up -d --build && docker-compose logs -f app
# libpq builds openssl as a dependency .PHONY: release
.PHONY: build build-release: builder
build: libpq cross build --target "$(TARGET)-musl" --release
.PHONY: clean
clean: clean-openssl clean-libpq clean-di
@ echo "Note: this only cleans the C dependencies, not the Cargo cache."
rm -rf "$(PREFIX)"
# This is used inside the Dockerfile
.PHONY: pathfile
pathfile:
echo "$(PREFIX)/lib" >> /etc/ld-musl-x86_64.path
## =====OPENSSL=====
# Download the source code & configure the project
$(OPENSSL_DIR)/Configure:
curl -sSL "https://www.openssl.org/source/openssl-$(SSL_VER).tar.gz" | \
tar -xzC "$(OUT_DIR)"
cd "$(OPENSSL_DIR)" && \
CC="$(CC) -idirafter /usr/include -idirafter /usr/include/x86_64-linux-gnu/" ./Configure \
no-zlib \
no-shared \
--prefix="$(PREFIX)" \
--openssldir="$(PREFIX)/ssl" \
linux-x86_64
# Build OpenSSL
.PHONY: openssl
openssl: $(OPENSSL_DIR)/Configure
cd "$(OPENSSL_DIR)" && env C_INCLUDE_PATH="$(PREFIX)/include" $(MAKE) depend 2> /dev/null
cd "$(OPENSSL_DIR)" && $(MAKE) -j$(CORES)
cd "$(OPENSSL_DIR)" && $(MAKE) install_sw
.PHONY: clean-openssl
clean-openssl:
rm -rf "$(OPENSSL_DIR)"
## =====LIBPQ=====
# Download the source code & configure the project
$(PQ_DIR)/configure:
curl -sSL "https://ftp.postgresql.org/pub/source/v$(PQ_VER)/postgresql-$(PQ_VER).tar.gz" | \
tar -xzC "$(OUT_DIR)"
cd "$(PQ_DIR)" && \
LDFLAGS="-L$(PREFIX)/lib" CFLAGS="-I$(PREFIX)/include" ./configure \
--without-readline \
--with-openssl \
--without-zlib \
--prefix="$(PREFIX)" \
--host=x86_64-unknown-linux-musl
.PHONY: libpq
libpq: openssl $(PQ_DIR)/configure
cd "$(PQ_DIR)/src/interfaces/libpq" && $(MAKE) -j$(CORES) all-static-lib
cd "$(PQ_DIR)/src/interfaces/libpq" && $(MAKE) install install-lib-static
cd "$(PQ_DIR)/src/bin/pg_config" && $(MAKE) -j$(CORES)
cd "$(PQ_DIR)/src/bin/pg_config" && $(MAKE) install
.PHONY: clean-libpq
clean-libpq:
rm -rf "$(PQ_DIR)"
# =====DUMB-INIT=====
# NOTE: this is only used inside the Docker image, but it's here for completeness.
$(DI_DIR)/Makefile:
curl -sSL "https://github.com/Yelp/dumb-init/archive/refs/tags/v$(DI_VER).tar.gz" | \
tar -C "$(OUT_DIR)" -xz
.PHONY: di
di: $(DI_DIR)/Makefile
make -C "$(DI_DIR)" build
.PHONY: clean-di
clean-di:
rm -rf "$(DI_DIR)"
# ====UTILITIES FOR DEVELOPMENT===== # ====UTILITIES FOR DEVELOPMENT=====
## The tests require a database, so we run them like this ## The tests require a database, so we run them like this

7
build.rs 100644
View File

@ -0,0 +1,7 @@
fn main() {
println!("cargo:rustc-link-lib=static=c");
println!("cargo:rustc-link-lib=static=dl");
println!("cargo:rustc-link-lib=static=ssl");
println!("cargo:rustc-link-lib=static=pq");
}

View File

@ -2,10 +2,11 @@
version: '3' version: '3'
services: services:
app:
build: '.'
db: db:
image: 'postgres:13-alpine' image: 'postgres:13-alpine'
restart: 'always' restart: 'always'
environment: environment:
- 'POSTGRES_DB=rb' - 'POSTGRES_DB=rb'
- 'POSTGRES_USER=rb' - 'POSTGRES_USER=rb'
@ -14,6 +15,5 @@ services:
- '5432:5432' - '5432:5432'
volumes: volumes:
- 'db-data:/var/lib/postgresql/data' - 'db-data:/var/lib/postgresql/data'
volumes: volumes:
db-data: db-data:

View File

@ -1,28 +0,0 @@
# vim: ft=dockerfile
FROM rust:1.54
ENV PREFIX="/usr/src/out/prefix" \
CC="musl-gcc -fPIC -pie -static" \
LD_LIBRARY_PATH="$PREFIX" \
PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" \
PATH="/usr/local/bin:/root/.cargo/bin:$PATH"
WORKDIR /usr/src/app
RUN groupadd -g 1000 builder && \
useradd -u 1000 -g 1000 builder && \
mkdir -p "$PREFIX" && \
chown -R builder:builder /usr/src/app && \
apt update && \
apt install -y --no-install-recommends \
musl-dev \
musl-tools \
libpq-dev \
libssl-dev && \
rustup target add x86_64-unknown-linux-musl && \
echo "$PREFIX/lib" >> /etc/ld-musl-x86_64.path
USER builder
CMD ["cargo", "test"]

View File

@ -2,11 +2,11 @@
// compilation succeeds in the release Docker image. // compilation succeeds in the release Docker image.
extern crate openssl; extern crate openssl;
#[macro_use] #[macro_use]
extern crate rocket; extern crate diesel;
#[macro_use] #[macro_use]
extern crate diesel_migrations; extern crate diesel_migrations;
#[macro_use] #[macro_use]
extern crate diesel; extern crate rocket;
use figment::{ use figment::{
providers::{Env, Format, Yaml}, providers::{Env, Format, Yaml},