# Build from source

> Host packages, PGRUST_PGSHAREDIR bake-in, cargo build --release --locked --bin postgres, wasm64 single-user notes, and binary location target/release/postgres.

- Repository: malisper/pgrust
- GitHub: https://github.com/malisper/pgrust
- Human docs: https://grok-wiki.com/public/docs/malisper-pgrust-7e0c8e82bc21
- Complete Markdown: https://grok-wiki.com/public/docs/malisper-pgrust-7e0c8e82bc21/llms-full.txt

## Source Files

- `README.md`
- `Cargo.toml`
- `.cargo/config.toml`
- `crates/_support/seam/init/Cargo.toml`
- `crates/wasm-libc-shim/src/lib.rs`
- `Dockerfile`

---

---
title: "Build from source"
description: "Host packages, PGRUST_PGSHAREDIR bake-in, cargo build --release --locked --bin postgres, wasm64 single-user notes, and binary location target/release/postgres."
---

The release server binary is the `postgres` bin from workspace package `init` (`crates/_support/seam/init`): one `[[bin]]` entry that creates the top memory context, runs `init::init_all` seam registration, then dispatches through `main_main::pg_main`. Native builds use `cargo build --release --locked --bin postgres` and emit `target/release/postgres`. Install-time share and path defaults are compile-time `option_env!("PGRUST_*")` values (primarily `PGRUST_PGSHAREDIR`) read from `backend/utils/init/miscinit` boot path helpers.

## Prerequisites

### Toolchain

| Requirement | Notes |
| --- | --- |
| Rust toolchain + Cargo | Workspace `edition = "2021"`. No `rust-version` pin in the root workspace. |
| `Cargo.lock` | Use `--locked` so the tree matches the committed lockfile. |
| Host C libraries | OpenSSL, ICU, LDAP, PAM (and related system libs) for native link of the ported backend FFI crates. |
| Share tree | Vendored Postgres 18.3 files under `vendor/postgres-18.3/share` (or an equivalent share dir at the path baked into the binary). |

`postgresql-client-18` / Homebrew `libpq` supply a Postgres 18 `psql` for connect and regression work; they are not required to link the server binary itself.

### Host packages

<Tabs>
  <Tab title="macOS (Homebrew)">

```bash
brew install icu4c openssl@3 libpq

export LIBRARY_PATH="$(brew --prefix openssl@3)/lib:${LIBRARY_PATH:-}"
export PKG_CONFIG_PATH="$(brew --prefix openssl@3)/lib/pkgconfig:$(brew --prefix icu4c)/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
export PATH="$(brew --prefix libpq)/bin:$PATH"
```

OpenSSL and OpenLDAP FFI `build.rs` units also probe `brew --prefix openssl@3` / `openldap` when `OPENSSL_*` / search paths are unset. PAM uses the macOS SDK `libpam`.

  </Tab>
  <Tab title="Debian / Ubuntu">

```bash
sudo apt-get update
sudo apt-get install -y build-essential pkg-config \
  libicu-dev libssl-dev libldap2-dev libpam0g-dev \
  postgresql-client-18
```

The Docker `rustbuild` stage installs the same core set: `build-essential`, `pkg-config`, `libicu-dev`, `libldap2-dev`, `libpam0g-dev`, `libssl-dev` on `rust:1-bookworm`.

  </Tab>
</Tabs>

## Build-time path bake-in

`crates/backend/utils/init/miscinit/src/boot_paths.rs` (and datetime path helpers) resolve installation directories with `option_env!("PGRUST_…")`, falling back to PostgreSQL’s documented `/usr/local/pgsql/…` layout when unset.

| Env var | Default if unset at compile time |
| --- | --- |
| `PGRUST_PGSHAREDIR` | `/usr/local/pgsql/share` |
| `PGRUST_PGBINDIR` | `/usr/local/pgsql/bin` |
| `PGRUST_PKGLIBDIR` | `/usr/local/pgsql/lib` |
| `PGRUST_SYSCONFDIR` | `/usr/local/pgsql/etc` |
| `PGRUST_INCLUDEDIR` | `/usr/local/pgsql/include` |
| `PGRUST_PKGINCLUDEDIR` | `/usr/local/pgsql/include` |
| `PGRUST_INCLUDEDIRSERVER` | `/usr/local/pgsql/include/server` |
| `PGRUST_LIBDIR` | `/usr/local/pgsql/lib` |
| `PGRUST_LOCALEDIR` | `/usr/local/pgsql/share/locale` |
| `PGRUST_DOCDIR` | `/usr/local/pgsql/share/doc` |
| `PGRUST_HTMLDIR` | `/usr/local/pgsql/share/doc` |
| `PGRUST_MANDIR` | `/usr/local/pgsql/share/man` |

`.cargo/config.toml` supplies workspace defaults when the process environment does not set them:

| Key | Value | Behavior |
| --- | --- | --- |
| `PGRUST_PGSHAREDIR` | `/tmp/pgrust_share` | Applied only if not already set (`force` is false). |
| `CARGO_INCREMENTAL` | `"0"` | Incremental compilation off for this workspace. |

<Warning>
`PGRUST_PGSHAREDIR` is compile-time. A wrong bake-in points timezone / timezonesets (and related share resolution) at the wrong tree and breaks boot. Prefer an explicit absolute path to a real share directory at build time. Runtime `-L` still supplies the share path for `--initdb` catalog files; tz layout follows the baked share dir.
</Warning>

Recommended local bake-in (repo checkout):

```bash
PGRUST_PGSHAREDIR="$PWD/vendor/postgres-18.3/share" \
cargo build --release --locked --bin postgres
```

Docker `rustbuild` sets `ENV PGRUST_PGSHAREDIR=${PG_SHAREDIR}` with `PG_SHAREDIR=/usr/share/postgresql/18` so the image binary matches the share tree copied into the final stage.

### Vendored share tree

`vendor/postgres-18.3/share` includes the files `--initdb` / `--boot` and runtime path helpers expect, including:

- `postgres.bki`, `system_constraints.sql`, `system_functions.sql`, `system_views.sql`
- `information_schema.sql`, `sql_features.txt`, `snowball_create.sql`
- config samples (`postgresql.conf.sample`, `pg_hba.conf.sample`, `pg_ident.conf.sample`, …)
- `timezone/`, `timezonesets/`, `tsearch_data/`, `extension/`

## Release build

The only workspace `[[bin]]` named `postgres` lives on package `init` (`crates/_support/seam/init`). That package aggregates seam registration for ported backend and contrib crates. On non-wasm targets it also depends on the pgrust `initdb` driver; on wasm that dependency is omitted.

### Command

```bash
PGRUST_PGSHAREDIR="$PWD/vendor/postgres-18.3/share" \
cargo build --release --locked --bin postgres
```

| Flag / input | Role |
| --- | --- |
| `--release` | Uses `[profile.release]`: `debug = 0`, `strip = "symbols"`, `lto = false`, `codegen-units = 1`. |
| `--locked` | Refuse to update `Cargo.lock`; matches Dockerfile and README. |
| `--bin postgres` | Builds the server entry shell only, not every workspace member as a binary. |
| `PGRUST_PGSHAREDIR` | Optional override of `.cargo/config.toml` default at compile time. |

Equivalent Docker stage command (with `CARGO_TARGET_DIR=/build/target`):

```bash
cargo build --release --locked --bin postgres
# then: cp /build/target/release/postgres /opt/pgrust-postgres
```

### Output location

| Build | Binary path |
| --- | --- |
| Default native release | `target/release/postgres` |
| Custom `CARGO_TARGET_DIR` | `$CARGO_TARGET_DIR/release/postgres` |
| Docker intermediate | staged as `/opt/pgrust-postgres`, installed as `/usr/local/bin/pgrust-postgres` (symlink/contract via entrypoint) |

Verify the artifact exists and is executable:

```bash
ls -l target/release/postgres
target/release/postgres --version
```

### Optional: package-scoped build

Smoke and harness comments also use:

```bash
PGRUST_PGSHAREDIR=/tmp/pgrust_share cargo build -p init --bin postgres
# older comments may say -p seams-init; the Cargo package name is `init`
```

## Post-build smoke (native)

After a successful release link, initialize and start with the same share path and the required runtime stack / IO settings:

```bash
target/release/postgres --initdb \
  -D /tmp/pgrust-data \
  -L "$PWD/vendor/postgres-18.3/share" \
  --no-locale \
  --encoding UTF8 \
  -U postgres

ulimit -s 65520

RUST_MIN_STACK=33554432 target/release/postgres \
  -D /tmp/pgrust-data \
  -F \
  -c listen_addresses= \
  -k /tmp \
  -p 5432 \
  -c io_method=sync \
  -c max_stack_depth=60000
```

Connect with a Postgres 18 client:

```bash
psql -h /tmp -p 5432 -U postgres -d postgres \
  -c "select version(), 1 + 1 as two"
```

## wasm64 single-user notes

The tree supports a `wasm64-unknown-unknown` single-user build for browser / harness bring-up. This is not the native multi-process postmaster path.

### Target linker config

`.cargo/config.toml`:

```toml
[target.wasm64-unknown-unknown]
rustflags = ["-C", "link-arg=--allow-undefined"]
```

Native crates still declare OpenSSL / libxml2 / locale `extern "C"` symbols. Single-user `--single` does not call those paths, but the linker must resolve them: `--allow-undefined` turns unresolved C symbols into wasm imports. Hosts fault only if those imports are actually invoked.

### `wasm-libc-shim`

Package `wasm-libc-shim` is a shared libc stand-in for `target_family = "wasm"`. Consumers shadow `libc` with:

```rust
#[cfg(target_family = "wasm")]
use wasm_libc_shim as libc;
```

On native targets the crate is empty. On wasm it supplies Linux-shaped constants/types, allocator-backed `malloc`/`free`, and ENOSYS / no-op stubs for fork, SysV IPC, sockets, signals, and raw FS ops that single-user never requires on the boot path.

### Package differences on wasm

From `crates/_support/seam/init/Cargo.toml`:

- **Not linked:** `initdb` (subprocess bootstrap driver) — `cfg(not(target_family = "wasm"))`.
- **Linked:** `wasm-libc-shim`, and `getrandom` with `features = ["custom"]` (pgcrypto → rand path). The `postgres` bin registers a wasm-only xorshift custom backend so the module links without OS entropy.

Wasm `main` also installs a panic hook that writes to host stderr (std stderr is a no-op on this target) and obtains argv from a host `pgvfs` import when `std::env::args()` is empty.

### Profiles

| Profile | Purpose | Key settings | Build sketch |
| --- | --- | --- | --- |
| `wasm-boot` | Single-user boot bring-up | `opt-level = "z"`, `debug = "line-tables-only"`, `strip = false`, `panic = "abort"`, `codegen-units = 16` | `cargo +nightly build -Zbuild-std=std,panic_unwind,panic_abort --bin postgres --target wasm64-unknown-unknown --profile wasm-boot` |
| `wasm-prod` | Deployed browser module (e.g. pgrust.com) | `opt-level = "s"`, `lto = true`, `strip = true`, `codegen-units = 1`, `panic = "abort"` | `cargo +nightly build -Zbuild-std=std,panic_abort --bin postgres --target wasm64-unknown-unknown --profile wasm-prod` then `wasm-opt -O2` |

<Note>
The wasm64 target hard-codes `panic=abort`. SQL errors that rely on `catch_unwind` recovery can abort the process; error-free statements are the supported single-user path for bring-up.
</Note>

FFI `build.rs` units for OpenSSL and libxml2 intentionally emit **no** native link lines when `CARGO_CFG_TARGET_FAMILY=wasm`.

## Cargo workspace build knobs (adjacent)

These affect day-to-day source builds but are not required for a single release binary:

| Surface | Role |
| --- | --- |
| `cargo fast-check` | Alias for `cargo check --profile fast-check` (lighter than full release link). |
| `[profile.dev]` | `debug = "line-tables-only"`, `incremental = false` (linking dominates cost). |
| `scripts/check-crate`, `scripts/gate-crate` | Per-crate validation; see workspace workflow docs. |

## Failure modes at build time

| Symptom | Likely cause |
| --- | --- |
| Unresolved `ssl` / `crypto` / ICU / LDAP / PAM | Missing host packages or macOS `LIBRARY_PATH` / `PKG_CONFIG_PATH` not pointing at Homebrew kegs. |
| Lockfile mismatch with `--locked` | Local tree out of sync with committed `Cargo.lock`; resolve intentionally, do not drop `--locked` for release parity. |
| Server boots with wrong / missing timezone data | `PGRUST_PGSHAREDIR` baked to a path that does not contain `timezone` / `timezonesets`. Rebuild with the correct absolute share path. |
| `cargo build --bin postgres` ambiguity | Should not occur: only package `init` defines `[[bin]] name = "postgres"`. Use `-p init` if multiple bins confuse tooling. |
| wasm link fails on native C libs | Ensure `--target wasm64-unknown-unknown` and the target `rustflags` in `.cargo/config.toml` are active. |
| wasm `getrandom` link error | Custom backend is registered only in the `postgres` bin; build that bin, not intermediate crates that pull `getrandom` without the registration. |

## Next

<CardGroup>
  <Card title="Installation" href="/installation">
    Prerequisites, system packages, share-dir wiring, and producing the release binary from a clone.
  </Card>
  <Card title="Install paths and share directory" href="/install-paths">
    PGRUST_PGSHAREDIR, runtime `-L`, vendored share contents, and tz path failures.
  </Card>
  <Card title="Quickstart" href="/quickstart">
    Build, `--initdb` with `-L`, start with stack and `io_method` settings, connect with psql.
  </Card>
  <Card title="Docker" href="/docker">
    Image build and official postgres-shaped run contract.
  </Card>
  <Card title="Workspace and crate checks" href="/workspace-workflow">
    fast-check profile, `scripts/check-crate`, and per-crate validation.
  </Card>
  <Card title="Configuration reference" href="/configuration-reference">
    Runtime GUCs and build-time `PGRUST_*` path env vars.
  </Card>
</CardGroup>
