Documentation
¶
Overview ¶
Package common provides shared interfaces and base implementations for package builders.
Package common provides shared interfaces and base implementations for package builders.
Package common provides shared functionality for cross-compilation toolchains.
Index ¶
- Variables
- func ValidateTargetArch(arch string) error
- func ValidateToolchain(targetArch, format string) error
- type BaseBuilder
- func (bb *BaseBuilder) ApplyOptions() error
- func (bb *BaseBuilder) BuildPackageName(extension string) string
- func (bb *BaseBuilder) CreateFileWalker() *files.Walker
- func (bb *BaseBuilder) DownloadAndExtractCrossDeps(deps []string, targetArch string) error
- func (bb *BaseBuilder) ExtractToRoot(packagePath string) error
- func (bb *BaseBuilder) FormatRelease(distroSuffixMap map[string]string)
- func (bb *BaseBuilder) InstallOrExtract(artifactsPath, buildDir, targetArch string) error
- func (bb *BaseBuilder) LogCrossCompilation(targetArch string)
- func (bb *BaseBuilder) LogPackageCreated(artifactPath string)
- func (bb *BaseBuilder) Prepare(makeDepends []string, targetArch string) error
- func (bb *BaseBuilder) PrepareBackupFilePaths() []string
- func (bb *BaseBuilder) PrepareEnvironment(golang bool, targetArch string) error
- func (bb *BaseBuilder) PrepareScriptletWithHelpers(body string) string
- func (bb *BaseBuilder) ProcessDependencies(depends []string) []string
- func (bb *BaseBuilder) SetTargetArchitecture(targetArch string)
- func (bb *BaseBuilder) SetupCcache() error
- func (bb *BaseBuilder) SetupCrossCompilationEnvironment(targetArch string) error
- func (bb *BaseBuilder) SetupEnvironmentDependencies(golang bool) []string
- func (bb *BaseBuilder) TranslateArchitecture()
- func (bb *BaseBuilder) Update() error
- type Builder
- type CrossToolchain
Constants ¶
This section is empty.
Variables ¶
var CrossToolchainMap = func() map[string]map[string]CrossToolchain { basePatterns := map[string]map[string]string{ constants.DistroDebian: { gccKey: gccFmtPattern, gppKey: gppFmtPattern, binutilsKey: binutilsFmtPat, additionalKey: libc6DevFmtPat, }, constants.DistroUbuntu: { gccKey: gccFmtPattern, gppKey: gppFmtPattern, binutilsKey: binutilsFmtPat, additionalKey: libc6DevFmtPat, }, constants.DistroFedora: { gccKey: gccFmtPattern, gppKey: gppCxxFmtPat, binutilsKey: binutilsFmtPat, additionalKey: "", }, constants.DistroArch: { gccKey: archGccFmtPat, gppKey: archGppFmtPat, binutilsKey: archBinFmtPat, additionalKey: "", }, } archSpecific := map[string]map[string]map[string]string{ constants.ArchI686: { constants.DistroArch: { gccKey: gccMultilibPkg, gppKey: gccCxxMultilib, binutilsKey: binutilsMultilib, }, }, constants.ArchX86_64: { constants.DistroFedora: { gccKey: gccX86FmtPat, gppKey: gppX86FmtPat, binutilsKey: binX86FmtPat, }, }, constants.ArchAarch64: { constants.DistroArch: { gccKey: aarch64ArchGcc, gppKey: aarch64ArchGpp, binutilsKey: "aarch64-linux-gnu-binutils", }, }, constants.ArchS390x: { constants.DistroFedora: { gccKey: gccS390xRH, gppKey: gppS390xRH, binutilsKey: binS390xRH, }, }, } archAdditional := map[string]map[string][]string{ constants.ArchAarch64: { constants.DistroDebian: {"libc6-dev-arm64-cross"}, constants.DistroUbuntu: {"libc6-dev-arm64-cross"}, }, constants.ArchArmv7: { constants.DistroDebian: {libc6DevArmhf}, constants.DistroUbuntu: {libc6DevArmhf}, }, constants.ArchArmv6: { constants.DistroDebian: {libc6DevArmhf}, constants.DistroUbuntu: {libc6DevArmhf}, }, constants.ArchI686: { constants.DistroArch: {lib32GccLibs}, constants.DistroDebian: {libc6DevI386}, constants.DistroUbuntu: {libc6DevI386}, }, constants.ArchX86_64: { constants.DistroDebian: {"libc6-dev-amd64-cross"}, constants.DistroUbuntu: {"libc6-dev-amd64-cross"}, }, constants.ArchPpc64le: { constants.DistroDebian: {"libc6-dev-ppc64el-cross"}, constants.DistroUbuntu: {"libc6-dev-ppc64el-cross"}, }, constants.ArchS390x: { constants.DistroDebian: {"libc6-dev-s390x-cross"}, constants.DistroUbuntu: {"libc6-dev-s390x-cross"}, }, constants.ArchRiscv64: { constants.DistroDebian: {"libc6-dev-riscv64-cross"}, constants.DistroUbuntu: {"libc6-dev-riscv64-cross"}, }, } archPatterns := map[string]string{ constants.ArchAarch64: constants.TripletAarch64Linux, constants.ArchArmv7: constants.TripletArmLinuxHf, constants.ArchArmv6: constants.TripletArmLinuxHf, constants.ArchI686: constants.TripletI686Linux, constants.ArchX86_64: "x86-64-linux-gnu", constants.ArchPpc64le: constants.TripletPpc64leLinux, constants.ArchS390x: constants.TripletS390xLinux, constants.ArchRiscv64: constants.TripletRiscv64Linux, } result := make(map[string]map[string]CrossToolchain) architectures := []string{ constants.ArchAarch64, constants.ArchArmv7, constants.ArchArmv6, constants.ArchI686, constants.ArchX86_64, constants.ArchPpc64le, constants.ArchS390x, constants.ArchRiscv64, } distributions := []string{ constants.DistroDebian, constants.DistroUbuntu, constants.DistroFedora, constants.DistroArch, } for _, arch := range architectures { result[arch] = make(map[string]CrossToolchain) for _, distro := range distributions { patterns, exists := basePatterns[distro] if !exists { continue } archPattern := arch if pattern, exists := archPatterns[arch]; exists { archPattern = pattern } gcc := fmt.Sprintf(patterns[gccKey], archPattern) gpp := fmt.Sprintf(patterns[gppKey], archPattern) binutils := fmt.Sprintf(patterns[binutilsKey], archPattern) if archOverrides, exists := archSpecific[arch]; exists { if distroOverrides, exists := archOverrides[distro]; exists { if override, exists := distroOverrides[gccKey]; exists { gcc = override } if override, exists := distroOverrides[gppKey]; exists { gpp = override } if override, exists := distroOverrides[binutilsKey]; exists { binutils = override } } } // Determine additional packages var additional []string if archAdd, exists := archAdditional[arch]; exists { if add, exists := archAdd[distro]; exists { additional = add } else if add, exists := archAdd[defaultKey]; exists { additional = add } } triple := archPatterns[arch] installCommands := make(map[string]string) switch distro { case constants.DistroDebian, constants.DistroUbuntu: installCommands[distro] = fmt.Sprintf("sudo apt-get install %s %s", gcc, gpp) case constants.DistroFedora: installCommands[distro] = fmt.Sprintf("sudo dnf install %s %s", gcc, gpp) case constants.DistroArch: installCommands[distro] = fmt.Sprintf("sudo pacman -S %s %s", gcc, gpp) case constants.DistroAlpine: installCommands[distro] = fmt.Sprintf("sudo apk add %s %s", gcc, gpp) } result[arch][distro] = CrossToolchain{ GCCPackage: gcc, GPlusPlusPackage: gpp, BinutilsPackage: binutils, AdditionalPackages: additional, Triple: triple, InstallCommands: installCommands, } } } return result }()
CrossToolchainMap maps target architectures to toolchain packages for each distribution.
var SkipToolchainValidation bool
SkipToolchainValidation controls whether cross-compilation toolchain validation is performed. This is set by command-line flags and used by PrepareEnvironment.
Functions ¶
func ValidateTargetArch ¶
ValidateTargetArch returns an error if arch is not a recognised cross-compilation target. Returns nil when arch is empty (native build) or known.
func ValidateToolchain ¶
ValidateToolchain checks if the required cross-compilation toolchain is available for the given target architecture and package format. It returns a detailed error message with installation instructions if the toolchain is missing.
APK (Alpine) format always returns an error: Alpine does not ship Linux-userspace cross-compiler packages. Use a native Alpine container or QEMU instead.
Types ¶
type BaseBuilder ¶
type BaseBuilder struct {
PKGBUILD *pkgbuild.PKGBUILD
Format string // Package format: "apk", "deb", "rpm", "pacman"
}
BaseBuilder provides common functionality that can be embedded in concrete builders.
func NewBaseBuilder ¶
func NewBaseBuilder(pkgBuild *pkgbuild.PKGBUILD, format string) *BaseBuilder
NewBaseBuilder creates a new base builder instance.
func (*BaseBuilder) ApplyOptions ¶
func (bb *BaseBuilder) ApplyOptions() error
ApplyOptions runs the PKGBUILD option handlers (strip, docs, libtool, etc.) against the package directory. This consolidates the duplicated options.Apply call across DEB, RPM, and Pacman builders.
func (*BaseBuilder) BuildPackageName ¶
func (bb *BaseBuilder) BuildPackageName(extension string) string
BuildPackageName constructs standardized package names for different formats. Used by: APK, DEB, Pacman Not used by: RPM (RPM does not include epoch in the filename, only in metadata)
func (*BaseBuilder) CreateFileWalker ¶
func (bb *BaseBuilder) CreateFileWalker() *files.Walker
CreateFileWalker creates a configured file walker for the package format.
func (*BaseBuilder) DownloadAndExtractCrossDeps ¶
func (bb *BaseBuilder) DownloadAndExtractCrossDeps(deps []string, targetArch string) error
DownloadAndExtractCrossDeps downloads runtime dependencies and extracts them directly to the root filesystem without registering them in the dpkg database. This avoids the circular dependency problem where arch-all meta-packages (e.g. carbonio-core) depend on arch-specific packages (e.g. carbonio-openldap) that conflict with the target-arch variants needed for cross-compilation.
The function partitions deps the same way as installCrossDeps: arch-all packages are downloaded unqualified, arch-specific ones are qualified with the target architecture (e.g. :arm64). All packages are extracted via dpkg -x (pure Go equivalent) so no dependency resolution occurs.
func (*BaseBuilder) ExtractToRoot ¶
func (bb *BaseBuilder) ExtractToRoot(packagePath string) error
ExtractToRoot extracts a package directly to the root filesystem (/). This extracts the package contents to the actual filesystem without using a sysroot directory.
func (*BaseBuilder) FormatRelease ¶
func (bb *BaseBuilder) FormatRelease(distroSuffixMap map[string]string)
FormatRelease formats the package release string with distribution-specific suffixes. For RPM packages: appends RPM distro suffix and codename (only when codename is set) For other formats: returns release unchanged Note: DEB has its own getRelease() method in pkg/builders/deb/dpkg.go with different fallback behavior—it always appends a distro suffix (codename or distro name) for proper repository targeting, while this method only appends when codename is set.
func (*BaseBuilder) InstallOrExtract ¶
func (bb *BaseBuilder) InstallOrExtract(artifactsPath, buildDir, targetArch string) error
InstallOrExtract extracts the built package to the root filesystem (/). This applies to both native and cross-compilation builds.
func (*BaseBuilder) LogCrossCompilation ¶
func (bb *BaseBuilder) LogCrossCompilation(targetArch string)
LogCrossCompilation logs cross-compilation build initiation if target architecture differs. This consolidates duplicated cross-compilation logging across builders.
func (*BaseBuilder) LogPackageCreated ¶
func (bb *BaseBuilder) LogPackageCreated(artifactPath string)
LogPackageCreated logs successful package creation with consistent formatting. When running under sudo, ownership of the artifact is transferred to the original invoking user so downstream consumers (CI agents, etc.) can read it without elevated privileges.
func (*BaseBuilder) Prepare ¶
func (bb *BaseBuilder) Prepare(makeDepends []string, targetArch string) error
Prepare installs build dependencies using the appropriate package manager. This consolidates duplicated Prepare methods across all builders.
func (*BaseBuilder) PrepareBackupFilePaths ¶
func (bb *BaseBuilder) PrepareBackupFilePaths() []string
PrepareBackupFilePaths ensures all backup file paths have a leading slash. This is required by RPM and some other package formats.
func (*BaseBuilder) PrepareEnvironment ¶
func (bb *BaseBuilder) PrepareEnvironment(golang bool, targetArch string) error
PrepareEnvironment sets up the build environment with necessary tools. This consolidates duplicated PrepareEnvironment methods across all builders. Toolchain validation is always skipped here: PrepareEnvironment is called by "yap prepare" whose job is to *install* the cross-compiler — the toolchain cannot be present before it is installed. Validation runs later during the build stage (builder.processFunction → SetupCrossCompilationEnvironment).
func (*BaseBuilder) PrepareScriptletWithHelpers ¶
func (bb *BaseBuilder) PrepareScriptletWithHelpers(body string) string
PrepareScriptletWithHelpers prepends the PKGBUILD helper function preamble to a scriptlet body. Returns the body unchanged if no preamble is needed.
func (*BaseBuilder) ProcessDependencies ¶
func (bb *BaseBuilder) ProcessDependencies(depends []string) []string
ProcessDependencies processes dependency strings with version operators. This consolidates the duplicated dependency processing logic across package formats.
func (*BaseBuilder) SetTargetArchitecture ¶
func (bb *BaseBuilder) SetTargetArchitecture(targetArch string)
SetTargetArchitecture sets the target architecture for cross-compilation and translates it. If targetArch is empty, it uses the current ArchComputed value. Architecture-independent packages (arch=any) are never overridden — they always produce arch-all packages regardless of the cross-compilation target. This consolidates the duplicated architecture handling pattern across all builders.
func (*BaseBuilder) SetupCcache ¶
func (bb *BaseBuilder) SetupCcache() error
SetupCcache checks if ccache is available and configures the build environment to use it. This function sets up environment variables to enable ccache for faster compilation. It uses a mutex to serialize access to os.Setenv to prevent race conditions in parallel builds.
Idempotent: returns immediately if YAP_CCACHE_SETUP is already set. The ccache configuration is process-global (os.Setenv), so re-running it for every package in a yap.json iteration only produces redundant log lines and pointless envMutex contention.
Note: SetupCcache and SetupCrossCompilationEnvironment write to the same CC/CXX variables. When both are needed for a build, the call site invokes SetupCcache first, then SetupCrossCompilationEnvironment, which overwrites CC/CXX with the cross-compiler and relies on CCACHE_PREFIX to wrap it. The memoization here is per-process, so a yap.json batch that mixes cross- and non-cross-arch builds will not re-run ccache setup between them — that pattern was already racy with the process-global os.Setenv approach and is tracked separately.
func (*BaseBuilder) SetupCrossCompilationEnvironment ¶
func (bb *BaseBuilder) SetupCrossCompilationEnvironment(targetArch string) error
SetupCrossCompilationEnvironment configures environment variables for cross-compilation. This function sets up environment variables for C/C++, Rust, and Go cross-compilation. It uses a mutex to serialize access to os.Setenv to prevent race conditions in parallel builds.
func (*BaseBuilder) SetupEnvironmentDependencies ¶
func (bb *BaseBuilder) SetupEnvironmentDependencies(golang bool) []string
SetupEnvironmentDependencies gets the build environment dependencies for the format.
func (*BaseBuilder) TranslateArchitecture ¶
func (bb *BaseBuilder) TranslateArchitecture()
TranslateArchitecture translates architecture names for the target package format.
func (*BaseBuilder) Update ¶
func (bb *BaseBuilder) Update() error
Update updates the package manager's package database. This consolidates duplicated Update methods across all builders. For DEB, --allow-insecure-repositories is passed so that apt writes Packages index files for unsigned extra repos (e.g. --repo flags) to /var/lib/apt/lists/. Without it, apt silently skips those repos and aptcache.Reload() cannot see their packages for arch classification.
type Builder ¶
type Builder interface {
// BuildPackage creates the package file at the specified artifacts path
BuildPackage(artifactsPath string, targetArch string) (string, error)
// PrepareFakeroot sets up the package metadata and prepares the build environment
PrepareFakeroot(artifactsPath string, targetArch string) error
// Prepare installs build dependencies and prepares the build environment
Prepare(makeDepends []string, targetArch string) error
// PrepareEnvironment sets up the build environment with necessary tools
PrepareEnvironment(golang bool, targetArch string) error
// Update updates the package manager's package database
Update() error
}
Builder defines the common interface that all package builders must implement. This unifies the behavior across different package formats (APK, DEB, RPM, Pacman).
type CrossToolchain ¶
type CrossToolchain struct {
// GCCPackage is the name of the GCC cross-compiler package
GCCPackage string
// GPlusPlusPackage is the name of the G++ cross-compiler package
GPlusPlusPackage string
// BinutilsPackage is the name of the binutils package for the target architecture
BinutilsPackage string
// AdditionalPackages are any additional packages needed for the toolchain
AdditionalPackages []string
// Triple is the GNU triplet for the target architecture
Triple string
// InstallCommands provides distribution-specific installation commands
InstallCommands map[string]string
}
CrossToolchain represents a cross-compilation toolchain for a specific target architecture.
func GetCrossToolchain ¶
func GetCrossToolchain(arch, distro string) (CrossToolchain, error)
GetCrossToolchain retrieves the toolchain for a given architecture and distribution.
func (*CrossToolchain) GetAllPackages ¶
func (ct *CrossToolchain) GetAllPackages() []string
GetAllPackages returns all packages needed for this toolchain.
func (*CrossToolchain) GetExecutableName ¶
func (ct *CrossToolchain) GetExecutableName(packageName string) string
GetExecutableName converts a package name to its actual cross-compiler executable name. Naming conventions differ by distribution:
- Debian/Ubuntu: gcc-aarch64-linux-gnu → aarch64-linux-gnu-gcc
- Fedora: gcc-c++-aarch64-linux-gnu → aarch64-linux-gnu-g++
- Arch: aarch64-linux-gnu-gcc → aarch64-linux-gnu-gcc (already correct)
- Alpine: gcc-aarch64 → aarch64-alpine-linux-musl-gcc
func (*CrossToolchain) GetPackagesByType ¶
func (ct *CrossToolchain) GetPackagesByType() map[string][]string
GetPackagesByType returns packages categorized by type.
func (*CrossToolchain) Validate ¶
func (ct *CrossToolchain) Validate() ([]string, error)
Validate checks if the required toolchain executables are available in PATH. It resolves package names to their actual executable names before checking.