go-devops/docs/build-system.md
Snider 481344a066 docs: add human-friendly documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 13:02:39 +00:00

6.1 KiB

title description
Build System Project detection, cross-compilation, code signing, and .core/build.yaml configuration.

Build System

The build/ package provides automatic project type detection, cross-compilation for multiple OS/architecture targets, artefact archiving with checksums, and code signing. Configuration lives in .core/build.yaml at the project root.

How it works

  1. Detect — Probes the project directory for marker files to determine the project type.
  2. Build — Runs the appropriate builder plugin for each configured target (OS/arch pair).
  3. Archive — Packages build outputs into compressed archives with SHA-256 checksums.
  4. Sign — Optionally signs binaries before archiving (macOS codesign, GPG, or Windows signtool).

Run with:

core build                # Build for configured targets
core build --ci           # All targets, JSON output for CI pipelines

Project detection

discovery.go probes marker files in priority order. The first match wins:

Marker file Detected type Builder
wails.json wails Wails v3 desktop app
go.mod go Standard Go binary
package.json node Node.js (stub)
composer.json php PHP (stub)
CMakeLists.txt cpp CMake C++
Dockerfile docker Docker buildx
*.yml (LinuxKit pattern) linuxkit LinuxKit VM image
Taskfile.yml taskfile Task CLI delegation

Builder interface

Each builder implements three methods:

type Builder interface {
    Name() string
    Detect(fs io.Medium, dir string) (bool, error)
    Build(ctx context.Context, cfg *Config, targets []Target) ([]Artifact, error)
}
  • Detect checks whether the builder should handle a given directory.
  • Build produces []Artifact, where each artefact has a file Path, OS, Arch, and a SHA-256 Checksum.

Builders

Go builder (go.go)

Runs go build with ldflags injection and cross-compilation via GOOS/GOARCH environment variables. Reads the entry point from build.yaml's project.main field.

Wails builder (wails.go)

Builds Wails v3 desktop applications with platform-specific packaging. Uses wails.json for application metadata.

Docker builder (docker.go)

Runs docker buildx build with optional multi-platform support and registry push.

C++ builder (cpp.go)

Runs CMake configure and build in a temporary directory. Requires CMakeLists.txt.

LinuxKit builder (linuxkit.go)

Produces multi-format VM images from LinuxKit YAML configurations. Output formats: ISO, qcow2, raw, VMDK.

Taskfile builder (taskfile.go)

Delegates to the task CLI, mapping build targets to Taskfile tasks. Used for projects that have not yet migrated to native builders.

Node and PHP stubs

Stub builders for Node.js and PHP projects. Node runs npm run build; PHP wraps Docker builds. Both are minimal and intended for extension.

Artefacts and checksums

Each builder produces []Artifact:

type Artifact struct {
    Path     string // File path of the built artefact
    OS       string // Target operating system
    Arch     string // Target architecture
    Checksum string // SHA-256 hash
}

Checksums are computed automatically and written to dist/*.sha256 files.

Archive formats

archive.go packages build outputs into compressed archives. Supported formats:

  • tar.gz — default for Linux/macOS
  • tar.xz — smaller archives (uses Borg's xz compression)
  • zip — default for Windows

Code signing

The signing/ sub-package implements a Signer interface with three backends:

Signer Platform Tool Key source
macOS darwin codesign Keychain identity
GPG any gpg --detach-sign GPG key ID
Windows windows signtool Certificate store

Each signer checks Available() at runtime to verify the signing tool exists. Signing runs after compilation, before archiving.

.core/build.yaml reference

version: 1

project:
  name: my-app              # Project name (used in archive filenames)
  description: My application
  main: ./cmd/my-app        # Go entry point (go/wails only)
  binary: my-app            # Output binary name

build:
  cgo: false                # Enable CGO (default: false)
  flags:
    - -trimpath             # Go build flags
  ldflags:
    - -s                    # Strip debug info
    - -w                    # Strip DWARF

targets:                    # Cross-compilation targets
  - os: linux
    arch: amd64
  - os: linux
    arch: arm64
  - os: darwin
    arch: arm64
  - os: windows
    arch: amd64

Field reference

Field Type Description
version int Config schema version (always 1)
project.name string Project name, used in archive filenames
project.description string Human-readable description
project.main string Go entry point path (e.g. ./cmd/myapp)
project.binary string Output binary filename
build.cgo bool Whether to enable CGO (default false)
build.flags []string Go build flags (e.g. -trimpath)
build.ldflags []string Linker flags (e.g. -s -w)
targets []Target List of OS/arch pairs to compile for
targets[].os string Target OS (linux, darwin, windows)
targets[].arch string Target architecture (amd64, arm64)

Generated configuration

Running core setup repo in a git repository auto-generates .core/build.yaml based on detected project type:

core setup repo              # Generates .core/build.yaml, release.yaml, test.yaml
core setup repo --dry-run    # Preview without writing files

Adding a new builder

  1. Create build/builders/mylang.go.
  2. Implement the Builder interface:
    • Name() returns a human-readable name.
    • Detect(fs, dir) checks for a marker file (e.g. myconfig.toml).
    • Build(ctx, cfg, targets) produces artefacts.
  3. Register the builder in build/buildcmd/.
  4. Write tests verifying Detect (marker present/absent) and Build (at minimum with a mock io.Medium).