package main import ( "errors" "flag" "fmt" "os" "path/filepath" "runtime" "strconv" "strings" "sync" "time" "git.milar.in/milarin/channel" ) // globals var ( ModulePath string ProjectName string Runner channel.Runner MaxConfigStringLength int ) // command line arguments var ( OS = flag.String("os", "", "comma-separated list of operating systems to compile for (empty for all)") Arch = flag.String("arch", "", "comma-separated list of architectures to compile for (empty for all)") OutputDir = flag.String("o", "output", "output directory") Silent = flag.Bool("s", false, "silent mode (no output)") NoCompress = flag.Bool("c", false, "dont compress any executables") NumThreads = flag.Int("t", runtime.NumCPU(), "amount of threads (0 = infinite)") ) 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 }