kernel-rpi-os-32/cmd/compile/main.go

179 lines
4 KiB
Go
Raw Normal View History

2022-03-23 09:18:38 +00:00
package main
import (
"bufio"
"flag"
"fmt"
"io"
"io/fs"
"log"
"os"
"os/user"
"path/filepath"
"runtime"
"strconv"
"strings"
"github.com/magefile/mage/sh"
)
func main() {
if err := run(); err != nil {
log.Println(err)
os.Exit(1)
}
}
func execCmd(env map[string]string, stdout io.Writer, stderr io.Writer, cmd string, args ...string) func(args ...string) error {
return func(args2 ...string) error {
fmt.Println(cmd, args2)
_, err := sh.Exec(env, stdout, stderr, cmd, append(args, args2...)...)
return err
}
}
var kernelFolderFlag = flag.String("kernel", "./linux-sources", "folder containing the kernel to compile")
func run() error {
flag.Parse()
// TODO new version check
kernelFolder, err := filepath.Abs(*kernelFolderFlag)
if err != nil {
return err
}
fmt.Println("[kernel]", kernelFolder)
dockerRun := execCmd(nil, os.Stdout, os.Stderr,
"docker",
"run",
"-it", // to forward interrupt signals
"--rm", // cleanup afterwards
"-v", kernelFolder+":/root/armhf",
"ghcr.io/oliverpool/crossbuild-armhf:impish-20220316",
)
// change the owner of the files inside docker to the current user
chown := func(folder string) error {
user, err := user.Current()
if err != nil {
return err
}
return dockerRun("chown", "-R", user.Uid+":"+user.Gid, folder)
}
// default raspberry pi config according to https://www.raspberrypi.com/documentation/computers/linux_kernel.html#cross-compiling-the-kernel
if err := dockerRun("make", "bcmrpi_defconfig"); err != nil {
return err
}
if err := chown(".config"); err != nil {
return err
}
// adjust config to add CONFIG_SQUASHFS
configPath := filepath.Join(kernelFolder, ".config")
err = adjustTextFile(configPath, func(line string) bool {
return strings.HasPrefix(line, "CONFIG_SQUASHFS=")
}, []string{
"CONFIG_SQUASHFS=y",
})
if err != nil {
return err
}
// compile kernel and dtbs
if err := dockerRun("make", "zImage", "dtbs", "-j"+strconv.Itoa(runtime.NumCPU())); err != nil {
return err
}
if err := chown("arch/arm/boot"); err != nil {
return err
}
bootFolder := filepath.Join(kernelFolder, "arch", "arm", "boot")
dstFolder := filepath.Join(".", "dist")
os.RemoveAll(dstFolder) // ignore any error
if err = os.MkdirAll(dstFolder, 0755); err != nil {
return err
}
// copy and rename kernel
if err = sh.Copy(filepath.Join(dstFolder, "vmlinuz"), filepath.Join(bootFolder, "zImage")); err != nil {
return err
}
// copy dtb files
files, err := filepath.Glob(filepath.Join(bootFolder, "dts", "bcm*-rpi-*.dtb"))
if err != nil {
return err
}
// copy config and cmdline files
files = append(files, "./gokrazy/cmdline.txt", "./gokrazy/config.txt")
for _, file := range files {
dtbName := filepath.Base(file)
if err = sh.Copy(filepath.Join(dstFolder, dtbName), file); err != nil {
return err
}
}
2022-03-23 10:19:46 +00:00
if err = os.WriteFile(filepath.Join(dstFolder, "placeholder.go"), []byte(`package dist
// empty package so we can use the go tool with this repository
`), 0755); err != nil {
return err
}
2022-03-23 09:18:38 +00:00
return nil
}
func adjustTextFile(path string, skipLine func(string) bool, appendLines []string) error {
b, stat, err := readFile(path) // read the whole file in memory, since we are going to overwrite it
if err != nil {
return err
}
dst, err := os.OpenFile(path, os.O_TRUNC|os.O_WRONLY, stat.Mode())
if err != nil {
return err
}
defer dst.Close()
w := bufio.NewWriter(dst)
for _, line := range strings.Split(string(b), "\n") {
if skipLine(line) {
continue
}
_, err = w.WriteString(line + "\n")
if err != nil {
return err
}
}
for _, line := range appendLines {
_, err = w.WriteString(line + "\n")
if err != nil {
return err
}
}
err = w.Flush()
if err != nil {
return err
}
return dst.Close()
}
func readFile(path string) ([]byte, fs.FileInfo, error) {
f, err := os.Open(path)
if err != nil {
return nil, nil, err
}
defer f.Close()
b, err := io.ReadAll(f)
if err != nil {
return b, nil, err
}
stats, err := f.Stat()
return b, stats, err
}