build-patterns.md

  1# Build Patterns
  2
  3Language-specific templates for AUR packages. These templates use
  4`cd "${pkgname}-${pkgver}"`, which suits suffix-less and `-bin` packages. For
  5`-git` packages, use `cd "$pkgname"` instead (the source entry
  6`"$pkgname::git+..."` clones into `$pkgname`).
  7
  8Based on the Arch Wiki's
  9[Go](https://wiki.archlinux.org/title/Go_package_guidelines) and
 10[Rust](https://wiki.archlinux.org/title/Rust_package_guidelines) package
 11guidelines.
 12
 13## Go
 14
 15`makedepends=('go')`
 16
 17### Module caching
 18
 19Keep Go modules in the build environment rather than polluting `~/go`:
 20
 21```bash
 22prepare() {
 23  cd "${pkgname}-${pkgver}"
 24  mkdir -p build/
 25  export GOPATH="${srcdir}"
 26  go mod download -modcacherw
 27}
 28```
 29
 30If upstream lacks `go.mod`, initialise it before downloading (file an issue upstream):
 31
 32```bash
 33prepare() {
 34  cd "$pkgname-$pkgver"
 35  go mod init "${url#https://}"
 36  go mod tidy
 37}
 38```
 39
 40### Building
 41
 42The standard approach exports CGO flags and uses `GOFLAGS`:
 43
 44```bash
 45build() {
 46  cd "${pkgname}-${pkgver}"
 47  export CGO_CPPFLAGS="${CPPFLAGS}"
 48  export CGO_CFLAGS="${CFLAGS}"
 49  export CGO_CXXFLAGS="${CXXFLAGS}"
 50  export CGO_LDFLAGS="${LDFLAGS}"
 51  export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
 52  go build -o build .
 53}
 54```
 55
 56When upstream embeds version info via `-ldflags`, pass flags explicitly instead:
 57
 58```bash
 59build() {
 60  cd "${pkgname}-${pkgver}"
 61  export CGO_CPPFLAGS="${CPPFLAGS}"
 62  export CGO_CFLAGS="${CFLAGS}"
 63  export CGO_CXXFLAGS="${CXXFLAGS}"
 64  export CGO_LDFLAGS="${LDFLAGS}"
 65  go build \
 66      -trimpath \
 67      -buildmode=pie \
 68      -mod=readonly \
 69      -modcacherw \
 70      -o build/"$pkgname" \
 71      -ldflags "-linkmode external -extldflags \"${LDFLAGS}\"" \
 72      .
 73}
 74```
 75
 76Use `-o build` with a `mkdir -p build/` in `prepare()` to control output
 77location. For projects with multiple binaries: `go build -o build ./cmd/...`
 78
 79If upstream uses a Makefile, verify it passes hardening flags — many overwrite
 80`GOFLAGS`. Bypass the Makefile if needed and invoke `go build` directly.
 81
 82### Testing and packaging
 83
 84```bash
 85check() {
 86  cd "${pkgname}-${pkgver}"
 87  go test ./...
 88}
 89
 90package() {
 91  cd "${pkgname}-${pkgver}"
 92  install -Dm755 build/"$pkgname" "$pkgdir"/usr/bin/"$pkgname"
 93}
 94```
 95
 96### FULL RELRO
 97
 98If `namcap` reports `ELF file lacks FULL RELRO`, add `-bindnow` to ldflags
 99(requires Go ≥ 1.23):
100
101```bash
102-ldflags "-linkmode external -extldflags \"${LDFLAGS}\" -bindnow"
103```
104
105Or in the `GOFLAGS` style:
106
107```bash
108export GOFLAGS="-buildmode=pie -trimpath -ldflags='-linkmode=external -bindnow' -mod=readonly -modcacherw"
109```
110
111### Vendored dependencies
112
113If upstream ships a `vendor/` directory with `modules.txt`, change
114`-mod=readonly` to `-mod=vendor`.
115
116## Rust
117
118`makedepends=('cargo')`
119
120### Source
121
122Prefer source tarballs or GitHub release archives. When unavailable, use
123crates.io:
124
125```bash
126source=("$pkgname-$pkgver.tar.gz::https://static.crates.io/crates/$pkgname/$pkgname-$pkgver.crate")
127```
128
129Note: crates.io archives often lack test files, license files, and other assets.
130
131### Prepare, build, check
132
133```bash
134prepare() {
135  cd "$pkgname-$pkgver"
136  export RUSTUP_TOOLCHAIN=stable
137  cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')"
138}
139
140build() {
141  cd "$pkgname-$pkgver"
142  export RUSTUP_TOOLCHAIN=stable
143  export CARGO_TARGET_DIR=target
144  cargo build --frozen --release --all-features
145}
146
147check() {
148  cd "$pkgname-$pkgver"
149  export RUSTUP_TOOLCHAIN=stable
150  export CARGO_TARGET_DIR=target
151  cargo test --frozen --all-features
152}
153```
154
155- `--locked` / `--frozen`: Respect `Cargo.lock` exactly for reproducible builds.
156- `CARGO_TARGET_DIR=target`: Avoids user-preference side effects outside chroots.
157- `RUSTUP_TOOLCHAIN=stable`: Ensures default toolchain (unnecessary if upstream has `rust-toolchain.toml`).
158- Do **not** use `--release` for `check()` — it enables optimisations that hide bugs.
159- For cargo workspaces (check for `[workspace]` in `Cargo.toml`), add `--workspace` to `cargo test`.
160
161### Packaging
162
163```bash
164package() {
165  cd "$pkgname-$pkgver"
166  install -Dm0755 -t "$pkgdir/usr/bin/" "target/release/$pkgname"
167}
168```
169
170For multiple binaries:
171
172```bash
173package() {
174  cd "$pkgname-$pkgver"
175  find target/release \
176      -maxdepth 1 \
177      -executable \
178      -type f \
179      -exec install -Dm0755 -t "$pkgdir/usr/bin/" {} +
180}
181```
182
183### VCS packages
184
185For `-git` packages where upstream doesn't keep `Cargo.lock` in sync between
186releases, add `cargo update` before `cargo fetch` in `prepare()`.