1*8fb009dcSAndroid Build Coastguard Worker// Copyright (c) 2024, Google Inc. 2*8fb009dcSAndroid Build Coastguard Worker// 3*8fb009dcSAndroid Build Coastguard Worker// Permission to use, copy, modify, and/or distribute this software for any 4*8fb009dcSAndroid Build Coastguard Worker// purpose with or without fee is hereby granted, provided that the above 5*8fb009dcSAndroid Build Coastguard Worker// copyright notice and this permission notice appear in all copies. 6*8fb009dcSAndroid Build Coastguard Worker// 7*8fb009dcSAndroid Build Coastguard Worker// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8*8fb009dcSAndroid Build Coastguard Worker// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9*8fb009dcSAndroid Build Coastguard Worker// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10*8fb009dcSAndroid Build Coastguard Worker// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11*8fb009dcSAndroid Build Coastguard Worker// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12*8fb009dcSAndroid Build Coastguard Worker// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13*8fb009dcSAndroid Build Coastguard Worker// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14*8fb009dcSAndroid Build Coastguard Worker 15*8fb009dcSAndroid Build Coastguard Worker// pregenerate manages generated files in BoringSSL 16*8fb009dcSAndroid Build Coastguard Workerpackage main 17*8fb009dcSAndroid Build Coastguard Worker 18*8fb009dcSAndroid Build Coastguard Workerimport ( 19*8fb009dcSAndroid Build Coastguard Worker "bytes" 20*8fb009dcSAndroid Build Coastguard Worker "encoding/json" 21*8fb009dcSAndroid Build Coastguard Worker "errors" 22*8fb009dcSAndroid Build Coastguard Worker "flag" 23*8fb009dcSAndroid Build Coastguard Worker "fmt" 24*8fb009dcSAndroid Build Coastguard Worker "os" 25*8fb009dcSAndroid Build Coastguard Worker "path/filepath" 26*8fb009dcSAndroid Build Coastguard Worker "runtime" 27*8fb009dcSAndroid Build Coastguard Worker "slices" 28*8fb009dcSAndroid Build Coastguard Worker "strings" 29*8fb009dcSAndroid Build Coastguard Worker "sync" 30*8fb009dcSAndroid Build Coastguard Worker 31*8fb009dcSAndroid Build Coastguard Worker "boringssl.googlesource.com/boringssl/util/build" 32*8fb009dcSAndroid Build Coastguard Worker) 33*8fb009dcSAndroid Build Coastguard Worker 34*8fb009dcSAndroid Build Coastguard Workervar ( 35*8fb009dcSAndroid Build Coastguard Worker check = flag.Bool("check", false, "Check whether any files need to be updated, without actually updating them") 36*8fb009dcSAndroid Build Coastguard Worker numWorkers = flag.Int("num-workers", runtime.NumCPU(), "Runs the given number of workers") 37*8fb009dcSAndroid Build Coastguard Worker dryRun = flag.Bool("dry-run", false, "Skip actually writing any files") 38*8fb009dcSAndroid Build Coastguard Worker perlPath = flag.String("perl", "perl", "Path to the perl command") 39*8fb009dcSAndroid Build Coastguard Worker list = flag.Bool("list", false, "List all generated files, rather than actually run them") 40*8fb009dcSAndroid Build Coastguard Worker) 41*8fb009dcSAndroid Build Coastguard Worker 42*8fb009dcSAndroid Build Coastguard Workerfunc runTask(t Task) error { 43*8fb009dcSAndroid Build Coastguard Worker expected, err := t.Run() 44*8fb009dcSAndroid Build Coastguard Worker if err != nil { 45*8fb009dcSAndroid Build Coastguard Worker return err 46*8fb009dcSAndroid Build Coastguard Worker } 47*8fb009dcSAndroid Build Coastguard Worker 48*8fb009dcSAndroid Build Coastguard Worker dst := t.Destination() 49*8fb009dcSAndroid Build Coastguard Worker dstPath := filepath.FromSlash(dst) 50*8fb009dcSAndroid Build Coastguard Worker if *check { 51*8fb009dcSAndroid Build Coastguard Worker actual, err := os.ReadFile(dstPath) 52*8fb009dcSAndroid Build Coastguard Worker if err != nil { 53*8fb009dcSAndroid Build Coastguard Worker if os.IsNotExist(err) { 54*8fb009dcSAndroid Build Coastguard Worker err = errors.New("missing file") 55*8fb009dcSAndroid Build Coastguard Worker } 56*8fb009dcSAndroid Build Coastguard Worker return err 57*8fb009dcSAndroid Build Coastguard Worker } 58*8fb009dcSAndroid Build Coastguard Worker 59*8fb009dcSAndroid Build Coastguard Worker if !bytes.Equal(expected, actual) { 60*8fb009dcSAndroid Build Coastguard Worker return errors.New("file out of date") 61*8fb009dcSAndroid Build Coastguard Worker } 62*8fb009dcSAndroid Build Coastguard Worker return nil 63*8fb009dcSAndroid Build Coastguard Worker } 64*8fb009dcSAndroid Build Coastguard Worker 65*8fb009dcSAndroid Build Coastguard Worker if *dryRun { 66*8fb009dcSAndroid Build Coastguard Worker fmt.Printf("Would write %d bytes to %q\n", len(expected), dst) 67*8fb009dcSAndroid Build Coastguard Worker return nil 68*8fb009dcSAndroid Build Coastguard Worker } 69*8fb009dcSAndroid Build Coastguard Worker 70*8fb009dcSAndroid Build Coastguard Worker if err := os.MkdirAll(filepath.Dir(dstPath), 0777); err != nil { 71*8fb009dcSAndroid Build Coastguard Worker return err 72*8fb009dcSAndroid Build Coastguard Worker } 73*8fb009dcSAndroid Build Coastguard Worker return os.WriteFile(dstPath, expected, 0666) 74*8fb009dcSAndroid Build Coastguard Worker} 75*8fb009dcSAndroid Build Coastguard Worker 76*8fb009dcSAndroid Build Coastguard Workertype taskError struct { 77*8fb009dcSAndroid Build Coastguard Worker dst string 78*8fb009dcSAndroid Build Coastguard Worker err error 79*8fb009dcSAndroid Build Coastguard Worker} 80*8fb009dcSAndroid Build Coastguard Worker 81*8fb009dcSAndroid Build Coastguard Workerfunc worker(taskChan <-chan Task, errorChan chan<- taskError, wg *sync.WaitGroup) { 82*8fb009dcSAndroid Build Coastguard Worker defer wg.Done() 83*8fb009dcSAndroid Build Coastguard Worker for t := range taskChan { 84*8fb009dcSAndroid Build Coastguard Worker if err := runTask(t); err != nil { 85*8fb009dcSAndroid Build Coastguard Worker errorChan <- taskError{t.Destination(), err} 86*8fb009dcSAndroid Build Coastguard Worker } 87*8fb009dcSAndroid Build Coastguard Worker } 88*8fb009dcSAndroid Build Coastguard Worker} 89*8fb009dcSAndroid Build Coastguard Worker 90*8fb009dcSAndroid Build Coastguard Workerfunc run() error { 91*8fb009dcSAndroid Build Coastguard Worker if _, err := os.Stat("BUILDING.md"); err != nil { 92*8fb009dcSAndroid Build Coastguard Worker return fmt.Errorf("must be run from BoringSSL source root") 93*8fb009dcSAndroid Build Coastguard Worker } 94*8fb009dcSAndroid Build Coastguard Worker 95*8fb009dcSAndroid Build Coastguard Worker buildJSON, err := os.ReadFile("build.json") 96*8fb009dcSAndroid Build Coastguard Worker if err != nil { 97*8fb009dcSAndroid Build Coastguard Worker return err 98*8fb009dcSAndroid Build Coastguard Worker } 99*8fb009dcSAndroid Build Coastguard Worker 100*8fb009dcSAndroid Build Coastguard Worker // Remove comments. For now, just do a very basic preprocessing step. If 101*8fb009dcSAndroid Build Coastguard Worker // needed, we can switch to something well-defined like one of the many 102*8fb009dcSAndroid Build Coastguard Worker // dozen different extended JSONs like JSON5. 103*8fb009dcSAndroid Build Coastguard Worker lines := bytes.Split(buildJSON, []byte("\n")) 104*8fb009dcSAndroid Build Coastguard Worker for i := range lines { 105*8fb009dcSAndroid Build Coastguard Worker if idx := bytes.Index(lines[i], []byte("//")); idx >= 0 { 106*8fb009dcSAndroid Build Coastguard Worker lines[i] = lines[i][:idx] 107*8fb009dcSAndroid Build Coastguard Worker } 108*8fb009dcSAndroid Build Coastguard Worker } 109*8fb009dcSAndroid Build Coastguard Worker buildJSON = bytes.Join(lines, []byte("\n")) 110*8fb009dcSAndroid Build Coastguard Worker 111*8fb009dcSAndroid Build Coastguard Worker var targetsIn map[string]InputTarget 112*8fb009dcSAndroid Build Coastguard Worker if err := json.Unmarshal(buildJSON, &targetsIn); err != nil { 113*8fb009dcSAndroid Build Coastguard Worker return fmt.Errorf("error decoding build config: %s", err) 114*8fb009dcSAndroid Build Coastguard Worker } 115*8fb009dcSAndroid Build Coastguard Worker 116*8fb009dcSAndroid Build Coastguard Worker var tasks []Task 117*8fb009dcSAndroid Build Coastguard Worker targetsOut := make(map[string]build.Target) 118*8fb009dcSAndroid Build Coastguard Worker for name, targetIn := range targetsIn { 119*8fb009dcSAndroid Build Coastguard Worker targetOut, targetTasks, err := targetIn.Pregenerate(name) 120*8fb009dcSAndroid Build Coastguard Worker if err != nil { 121*8fb009dcSAndroid Build Coastguard Worker return err 122*8fb009dcSAndroid Build Coastguard Worker } 123*8fb009dcSAndroid Build Coastguard Worker targetsOut[name] = targetOut 124*8fb009dcSAndroid Build Coastguard Worker tasks = append(tasks, targetTasks...) 125*8fb009dcSAndroid Build Coastguard Worker } 126*8fb009dcSAndroid Build Coastguard Worker 127*8fb009dcSAndroid Build Coastguard Worker tasks = append(tasks, MakeBuildFiles(targetsOut)...) 128*8fb009dcSAndroid Build Coastguard Worker tasks = append(tasks, NewSimpleTask("gen/README.md", func() ([]byte, error) { 129*8fb009dcSAndroid Build Coastguard Worker return []byte(readme), nil 130*8fb009dcSAndroid Build Coastguard Worker })) 131*8fb009dcSAndroid Build Coastguard Worker 132*8fb009dcSAndroid Build Coastguard Worker // Filter tasks by command-line argument. 133*8fb009dcSAndroid Build Coastguard Worker if args := flag.Args(); len(args) != 0 { 134*8fb009dcSAndroid Build Coastguard Worker var filtered []Task 135*8fb009dcSAndroid Build Coastguard Worker for _, t := range tasks { 136*8fb009dcSAndroid Build Coastguard Worker dst := t.Destination() 137*8fb009dcSAndroid Build Coastguard Worker for _, arg := range args { 138*8fb009dcSAndroid Build Coastguard Worker if strings.Contains(dst, arg) { 139*8fb009dcSAndroid Build Coastguard Worker filtered = append(filtered, t) 140*8fb009dcSAndroid Build Coastguard Worker break 141*8fb009dcSAndroid Build Coastguard Worker } 142*8fb009dcSAndroid Build Coastguard Worker } 143*8fb009dcSAndroid Build Coastguard Worker } 144*8fb009dcSAndroid Build Coastguard Worker tasks = filtered 145*8fb009dcSAndroid Build Coastguard Worker } 146*8fb009dcSAndroid Build Coastguard Worker 147*8fb009dcSAndroid Build Coastguard Worker if *list { 148*8fb009dcSAndroid Build Coastguard Worker paths := make([]string, len(tasks)) 149*8fb009dcSAndroid Build Coastguard Worker for i, t := range tasks { 150*8fb009dcSAndroid Build Coastguard Worker paths[i] = t.Destination() 151*8fb009dcSAndroid Build Coastguard Worker } 152*8fb009dcSAndroid Build Coastguard Worker slices.Sort(paths) 153*8fb009dcSAndroid Build Coastguard Worker for _, p := range paths { 154*8fb009dcSAndroid Build Coastguard Worker fmt.Println(p) 155*8fb009dcSAndroid Build Coastguard Worker } 156*8fb009dcSAndroid Build Coastguard Worker return nil 157*8fb009dcSAndroid Build Coastguard Worker } 158*8fb009dcSAndroid Build Coastguard Worker 159*8fb009dcSAndroid Build Coastguard Worker // Schedule tasks in parallel. Perlasm benefits from running in parallel. The 160*8fb009dcSAndroid Build Coastguard Worker // others likely do not, but it is simpler to parallelize them all. 161*8fb009dcSAndroid Build Coastguard Worker var wg sync.WaitGroup 162*8fb009dcSAndroid Build Coastguard Worker taskChan := make(chan Task, *numWorkers) 163*8fb009dcSAndroid Build Coastguard Worker errorChan := make(chan taskError, *numWorkers) 164*8fb009dcSAndroid Build Coastguard Worker for i := 0; i < *numWorkers; i++ { 165*8fb009dcSAndroid Build Coastguard Worker wg.Add(1) 166*8fb009dcSAndroid Build Coastguard Worker go worker(taskChan, errorChan, &wg) 167*8fb009dcSAndroid Build Coastguard Worker } 168*8fb009dcSAndroid Build Coastguard Worker 169*8fb009dcSAndroid Build Coastguard Worker go func() { 170*8fb009dcSAndroid Build Coastguard Worker for _, t := range tasks { 171*8fb009dcSAndroid Build Coastguard Worker taskChan <- t 172*8fb009dcSAndroid Build Coastguard Worker } 173*8fb009dcSAndroid Build Coastguard Worker close(taskChan) 174*8fb009dcSAndroid Build Coastguard Worker wg.Wait() 175*8fb009dcSAndroid Build Coastguard Worker close(errorChan) 176*8fb009dcSAndroid Build Coastguard Worker }() 177*8fb009dcSAndroid Build Coastguard Worker 178*8fb009dcSAndroid Build Coastguard Worker var failed bool 179*8fb009dcSAndroid Build Coastguard Worker for err := range errorChan { 180*8fb009dcSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "Error in file %q: %s\n", err.dst, err.err) 181*8fb009dcSAndroid Build Coastguard Worker failed = true 182*8fb009dcSAndroid Build Coastguard Worker } 183*8fb009dcSAndroid Build Coastguard Worker if failed { 184*8fb009dcSAndroid Build Coastguard Worker return errors.New("some files had errors") 185*8fb009dcSAndroid Build Coastguard Worker } 186*8fb009dcSAndroid Build Coastguard Worker return nil 187*8fb009dcSAndroid Build Coastguard Worker} 188*8fb009dcSAndroid Build Coastguard Worker 189*8fb009dcSAndroid Build Coastguard Workerfunc main() { 190*8fb009dcSAndroid Build Coastguard Worker flag.Parse() 191*8fb009dcSAndroid Build Coastguard Worker if err := run(); err != nil { 192*8fb009dcSAndroid Build Coastguard Worker fmt.Fprintf(os.Stderr, "Error: %s\n", err) 193*8fb009dcSAndroid Build Coastguard Worker os.Exit(1) 194*8fb009dcSAndroid Build Coastguard Worker } 195*8fb009dcSAndroid Build Coastguard Worker} 196*8fb009dcSAndroid Build Coastguard Worker 197*8fb009dcSAndroid Build Coastguard Workerconst readme = `# Pre-generated files 198*8fb009dcSAndroid Build Coastguard Worker 199*8fb009dcSAndroid Build Coastguard WorkerThis directory contains a number of pre-generated build artifacts. To simplify 200*8fb009dcSAndroid Build Coastguard Workerdownstream builds, they are checked into the repository, rather than dynamically 201*8fb009dcSAndroid Build Coastguard Workergenerated as part of the build. 202*8fb009dcSAndroid Build Coastguard Worker 203*8fb009dcSAndroid Build Coastguard WorkerWhen developing on BoringSSL, if any inputs to these files are modified, callers 204*8fb009dcSAndroid Build Coastguard Workermust run the following command to update the generated files: 205*8fb009dcSAndroid Build Coastguard Worker 206*8fb009dcSAndroid Build Coastguard Worker go run ./util/pregenerate 207*8fb009dcSAndroid Build Coastguard Worker 208*8fb009dcSAndroid Build Coastguard WorkerTo check that files are up-to-date without updating files, run: 209*8fb009dcSAndroid Build Coastguard Worker 210*8fb009dcSAndroid Build Coastguard Worker go run ./util/pregenerate -check 211*8fb009dcSAndroid Build Coastguard Worker 212*8fb009dcSAndroid Build Coastguard WorkerThis is run on CI to ensure the generated files remain up-to-date. 213*8fb009dcSAndroid Build Coastguard Worker 214*8fb009dcSAndroid Build Coastguard WorkerTo speed up local iteration, the tool accepts additional arguments to filter the 215*8fb009dcSAndroid Build Coastguard Workerfiles generated. For example, if editing ` + "`aesni-x86_64.pl`" + `, this 216*8fb009dcSAndroid Build Coastguard Workercommand will only update files with "aesni-x86_64" as a substring. 217*8fb009dcSAndroid Build Coastguard Worker 218*8fb009dcSAndroid Build Coastguard Worker go run ./util/pregenerate aesni-x86_64 219*8fb009dcSAndroid Build Coastguard Worker 220*8fb009dcSAndroid Build Coastguard WorkerFor convenience, all files in this directory, including this README, are managed 221*8fb009dcSAndroid Build Coastguard Workerby the tool. This means the whole directory may be deleted and regenerated from 222*8fb009dcSAndroid Build Coastguard Workerscratch at any time. 223*8fb009dcSAndroid Build Coastguard Worker` 224