133 lines
2.9 KiB
Go
133 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"text/template"
|
|
"time"
|
|
|
|
"git.milar.in/milarin/channel"
|
|
)
|
|
|
|
// globals
|
|
var (
|
|
OutputFileTmpl = template.New("output-file")
|
|
|
|
ModulePath string
|
|
ProjectName string
|
|
Runner channel.Runner
|
|
|
|
MaxConfigStringLength int
|
|
)
|
|
|
|
// command line arguments default values
|
|
var (
|
|
DefaultOutputDir = "output"
|
|
DefaultOutputFile = "{{.Name}}-{{.OS}}-{{.Arch}}{{.Ext}}"
|
|
DefaultOS = ""
|
|
DefaultArch = ""
|
|
DefaultSilent = false
|
|
DefaultNoCompress = false
|
|
DefaultNumThreads = runtime.NumCPU()
|
|
)
|
|
|
|
// command line arguments
|
|
var (
|
|
OutputDir = flag.String("o", DefaultOutputDir, "output directory")
|
|
OutputFile = flag.String("f", DefaultOutputFile, "go template for filenames")
|
|
|
|
OS = flag.String("os", DefaultOS, "comma-separated list of operating systems to compile for (empty for all)")
|
|
Arch = flag.String("arch", DefaultArch, "comma-separated list of architectures to compile for (empty for all)")
|
|
|
|
Silent = flag.Bool("s", DefaultSilent, "silent mode (no output)")
|
|
NoCompress = flag.Bool("c", DefaultNoCompress, "dont compress any executables")
|
|
NumThreads = flag.Int("t", DefaultNumThreads, "amount of threads (0 = infinite)")
|
|
|
|
SaveConfigFile = flag.Bool("saveconfig", false, "save config file with current configuration and exit")
|
|
IgnoreConfigFile = flag.Bool("ignoreconfig", false, "dont read any config file")
|
|
FindConfigFile = flag.Bool("findconfig", false, "print config file path and exit")
|
|
)
|
|
|
|
func main() {
|
|
Init()
|
|
|
|
ch := make(chan *CompileReport, len(CompileConfigs))
|
|
wg := new(sync.WaitGroup)
|
|
|
|
doneCh := make(chan struct{})
|
|
go Watch(ch, doneCh)
|
|
|
|
Runner = GetRunner()
|
|
|
|
start := time.Now()
|
|
|
|
for _, cfg := range CompileConfigs {
|
|
cfg := cfg
|
|
wg.Add(1)
|
|
go Runner.Run(func() { Compile(cfg, ch, wg) })
|
|
}
|
|
|
|
wg.Wait()
|
|
close(ch)
|
|
|
|
end := time.Now()
|
|
|
|
<-doneCh // wait for Watch routine
|
|
|
|
if !*Silent {
|
|
fmt.Printf("compilation took %s (using %s threads)\n", end.Sub(start), GetThreadCountString())
|
|
}
|
|
}
|
|
|
|
func DetermineProjectName() error {
|
|
data, err := os.ReadFile(filepath.Join(ModulePath, "go.mod"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, line := range strings.Split(string(data), "\n") {
|
|
if strings.HasPrefix(line, "module ") {
|
|
fullName := strings.TrimPrefix(line, "module ")
|
|
parts := strings.Split(fullName, "/")
|
|
ProjectName = parts[len(parts)-1]
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return errors.New("malformed syntax in go.mod file")
|
|
}
|
|
|
|
func GetRunner() channel.Runner {
|
|
if *NumThreads <= 0 {
|
|
return channel.NewUnlimitedRunner()
|
|
} else {
|
|
return channel.NewLimitedRunner(*NumThreads)
|
|
}
|
|
}
|
|
|
|
func GetThreadCountString() string {
|
|
if *NumThreads == 0 {
|
|
return "infinitely many"
|
|
}
|
|
return strconv.Itoa(*NumThreads)
|
|
}
|
|
|
|
func CheckDirWritable(dir string) error {
|
|
path := filepath.Join(*OutputDir, ".gocc")
|
|
|
|
file, err := os.Create(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
file.Close()
|
|
os.Remove(path)
|
|
return nil
|
|
}
|