# Build Patterns

Language-specific templates for AUR packages. These templates use
`cd "${pkgname}-${pkgver}"`, which suits suffix-less and `-bin` packages. For
`-git` packages, use `cd "$pkgname"` instead (the source entry
`"$pkgname::git+..."` clones into `$pkgname`).

Based on the Arch Wiki's
[Go](https://wiki.archlinux.org/title/Go_package_guidelines) and
[Rust](https://wiki.archlinux.org/title/Rust_package_guidelines) package
guidelines.

## Go

`makedepends=('go')`

### Module caching

Keep Go modules in the build environment rather than polluting `~/go`:

```bash
prepare() {
  cd "${pkgname}-${pkgver}"
  mkdir -p build/
  export GOPATH="${srcdir}"
  go mod download -modcacherw
}
```

If upstream lacks `go.mod`, initialise it before downloading (file an issue upstream):

```bash
prepare() {
  cd "$pkgname-$pkgver"
  go mod init "${url#https://}"
  go mod tidy
}
```

### Building

The standard approach exports CGO flags and uses `GOFLAGS`:

```bash
build() {
  cd "${pkgname}-${pkgver}"
  export CGO_CPPFLAGS="${CPPFLAGS}"
  export CGO_CFLAGS="${CFLAGS}"
  export CGO_CXXFLAGS="${CXXFLAGS}"
  export CGO_LDFLAGS="${LDFLAGS}"
  export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
  go build -o build .
}
```

When upstream embeds version info via `-ldflags`, pass flags explicitly instead:

```bash
build() {
  cd "${pkgname}-${pkgver}"
  export CGO_CPPFLAGS="${CPPFLAGS}"
  export CGO_CFLAGS="${CFLAGS}"
  export CGO_CXXFLAGS="${CXXFLAGS}"
  export CGO_LDFLAGS="${LDFLAGS}"
  go build \
      -trimpath \
      -buildmode=pie \
      -mod=readonly \
      -modcacherw \
      -o build/"$pkgname" \
      -ldflags "-linkmode external -extldflags \"${LDFLAGS}\"" \
      .
}
```

Use `-o build` with a `mkdir -p build/` in `prepare()` to control output
location. For projects with multiple binaries: `go build -o build ./cmd/...`

If upstream uses a Makefile, verify it passes hardening flags — many overwrite
`GOFLAGS`. Bypass the Makefile if needed and invoke `go build` directly.

### Testing and packaging

```bash
check() {
  cd "${pkgname}-${pkgver}"
  go test ./...
}

package() {
  cd "${pkgname}-${pkgver}"
  install -Dm755 build/"$pkgname" "$pkgdir"/usr/bin/"$pkgname"
}
```

### FULL RELRO

If `namcap` reports `ELF file lacks FULL RELRO`, add `-bindnow` to ldflags
(requires Go ≥ 1.23):

```bash
-ldflags "-linkmode external -extldflags \"${LDFLAGS}\" -bindnow"
```

Or in the `GOFLAGS` style:

```bash
export GOFLAGS="-buildmode=pie -trimpath -ldflags='-linkmode=external -bindnow' -mod=readonly -modcacherw"
```

### Vendored dependencies

If upstream ships a `vendor/` directory with `modules.txt`, change
`-mod=readonly` to `-mod=vendor`.

## Rust

`makedepends=('cargo')`

### Source

Prefer source tarballs or GitHub release archives. When unavailable, use
crates.io:

```bash
source=("$pkgname-$pkgver.tar.gz::https://static.crates.io/crates/$pkgname/$pkgname-$pkgver.crate")
```

Note: crates.io archives often lack test files, license files, and other assets.

### Prepare, build, check

```bash
prepare() {
  cd "$pkgname-$pkgver"
  export RUSTUP_TOOLCHAIN=stable
  cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')"
}

build() {
  cd "$pkgname-$pkgver"
  export RUSTUP_TOOLCHAIN=stable
  export CARGO_TARGET_DIR=target
  cargo build --frozen --release --all-features
}

check() {
  cd "$pkgname-$pkgver"
  export RUSTUP_TOOLCHAIN=stable
  export CARGO_TARGET_DIR=target
  cargo test --frozen --all-features
}
```

- `--locked` / `--frozen`: Respect `Cargo.lock` exactly for reproducible builds.
- `CARGO_TARGET_DIR=target`: Avoids user-preference side effects outside chroots.
- `RUSTUP_TOOLCHAIN=stable`: Ensures default toolchain (unnecessary if upstream has `rust-toolchain.toml`).
- Do **not** use `--release` for `check()` — it enables optimisations that hide bugs.
- For cargo workspaces (check for `[workspace]` in `Cargo.toml`), add `--workspace` to `cargo test`.

### Packaging

```bash
package() {
  cd "$pkgname-$pkgver"
  install -Dm0755 -t "$pkgdir/usr/bin/" "target/release/$pkgname"
}
```

For multiple binaries:

```bash
package() {
  cd "$pkgname-$pkgver"
  find target/release \
      -maxdepth 1 \
      -executable \
      -type f \
      -exec install -Dm0755 -t "$pkgdir/usr/bin/" {} +
}
```

### VCS packages

For `-git` packages where upstream doesn't keep `Cargo.lock` in sync between
releases, add `cargo update` before `cargo fetch` in `prepare()`.
