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 and Rust package guidelines.
Go
makedepends=('go')
Module caching
Keep Go modules in the build environment rather than polluting ~/go:
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):
prepare() {
cd "$pkgname-$pkgver"
go mod init "${url#https://}"
go mod tidy
}
Building
The standard approach exports CGO flags and uses GOFLAGS:
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:
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
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):
-ldflags "-linkmode external -extldflags \"${LDFLAGS}\" -bindnow"
Or in the GOFLAGS style:
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:
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
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: RespectCargo.lockexactly for reproducible builds.CARGO_TARGET_DIR=target: Avoids user-preference side effects outside chroots.RUSTUP_TOOLCHAIN=stable: Ensures default toolchain (unnecessary if upstream hasrust-toolchain.toml).- Do not use
--releaseforcheck()— it enables optimisations that hide bugs. - For cargo workspaces (check for
[workspace]inCargo.toml), add--workspacetocargo test.
Packaging
package() {
cd "$pkgname-$pkgver"
install -Dm0755 -t "$pkgdir/usr/bin/" "target/release/$pkgname"
}
For multiple binaries:
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().