diff --git a/internal/rosa/cmake.go b/internal/rosa/cmake.go index 3468d1d..ef91a72 100644 --- a/internal/rosa/cmake.go +++ b/internal/rosa/cmake.go @@ -1,6 +1,12 @@ package rosa -import "hakurei.app/internal/pkg" +import ( + "slices" + "strings" + + "hakurei.app/container/check" + "hakurei.app/internal/pkg" +) // NewCMake returns a [pkg.Artifact] containing an installation of CMake. func (t Toolchain) NewCMake() pkg.Artifact { @@ -29,3 +35,93 @@ make DESTDIR=/work install pkg.TarGzip, ))) } + +// CMakeAttr holds the project-specific attributes that will be applied to a new +// [pkg.Artifact] compiled via CMake. +type CMakeAttr struct { + // Path elements joined with source. + Append []string + // Use source tree as scratch space. + Writable bool + // Dependencies concatenated with the build system itself. + Extra []pkg.Artifact + + // CMake CACHE entries. + Cache [][2]string + // Additional environment variables. + Env []string + // Runs before cmake. + ScriptEarly string + // Runs after cmake. + Script string + + // Override the default installation prefix [AbsSystem]. + Prefix *check.Absolute +} + +// NewViaCMake returns a [pkg.Artifact] for compiling and installing via CMake. +func (t Toolchain) NewViaCMake( + name, version, variant string, + source pkg.Artifact, + attr *CMakeAttr, +) pkg.Artifact { + if name == "" || version == "" || variant == "" { + panic("names must be non-empty") + } + if attr == nil { + attr = &CMakeAttr{ + Cache: [][2]string{ + {"CMAKE_BUILD_TYPE", "Release"}, + }, + } + } + if len(attr.Cache) == 0 { + panic("CACHE must be non-empty") + } + + cmakeExtras := []pkg.Artifact{ + t.NewCMake(), + t.NewNinja(), + } + if t == toolchainStage3 { + cmakeExtras = nil + } + + scriptEarly := attr.ScriptEarly + if attr.Writable { + scriptEarly = ` +chmod -R +w "${ROSA_CMAKE_SOURCE}" +` + scriptEarly + } + + prefix := attr.Prefix + if prefix == nil { + prefix = AbsSystem + } + + sourcePath := AbsUsrSrc.Append(name) + return t.New(name+"-"+variant+"-"+version, slices.Concat( + attr.Extra, + cmakeExtras, + ), nil, slices.Concat([]string{ + "ROSA_CMAKE_SOURCE=" + sourcePath.Append(attr.Append...).String(), + "ROSA_INSTALL_PREFIX=/work" + prefix.String(), + }, attr.Env), scriptEarly+` +cd "$(mktemp -d)" +cmake -G Ninja \ + -DCMAKE_C_COMPILER_TARGET="${ROSA_TRIPLE}" \ + -DCMAKE_CXX_COMPILER_TARGET="${ROSA_TRIPLE}" \ + -DCMAKE_ASM_COMPILER_TARGET="${ROSA_TRIPLE}" \ + `+strings.Join(slices.Collect(func(yield func(string) bool) { + for _, v := range attr.Cache { + if !yield("-D" + v[0] + "=" + v[1]) { + return + } + } + }), " \\\n\t")+` \ + -DCMAKE_INSTALL_PREFIX="${ROSA_INSTALL_PREFIX}" \ + "${ROSA_CMAKE_SOURCE}" +cmake --build . +cmake --install . +`+attr.Script, pkg.Path(sourcePath, attr.Writable, source)) +}