github.com/maruel/nin@v0.0.0-20220112143044-f35891e3ce7e/manifest_parser.go (about) 1 // Copyright 2011 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package nin 16 17 // ParseManifestConcurrency defines the concurrency parameters when parsing 18 // manifest (build.ninja files). 19 type ParseManifestConcurrency int32 20 21 const ( 22 // ParseManifestSerial parses files serially in the same way that the C++ 23 // ninja implementation does. It is the most compatible way. 24 // 25 // This reduces CPU usage, at the cost of higher latency. 26 ParseManifestSerial ParseManifestConcurrency = iota 27 // ParseManifestPrewarmSubninja loads files serially except that subninjas 28 // are processed at the very end. This gives a latency improvement when a 29 // significant number of subninjas are processed because subninja files can 30 // be read from disk concurrently. This causes subninja files to be processed 31 // out of order. 32 ParseManifestPrewarmSubninja 33 // ParseManifestConcurrentParsing parses all subninjas concurrently. 34 ParseManifestConcurrentParsing 35 ) 36 37 func (p ParseManifestConcurrency) String() string { 38 switch p { 39 case ParseManifestSerial: 40 return "Serial" 41 case ParseManifestPrewarmSubninja: 42 return "PrewarmSubninja" 43 case ParseManifestConcurrentParsing: 44 return "Concurrent" 45 default: 46 return "Invalid" 47 } 48 } 49 50 // ParseManifestOpts are the options when parsing a build.ninja file. 51 type ParseManifestOpts struct { 52 // ErrOnDupeEdge causes duplicate rules for one target to print an error, 53 // otherwise warns. 54 ErrOnDupeEdge bool 55 // ErrOnPhonyCycle causes phony cycles to print an error, otherwise warns. 56 ErrOnPhonyCycle bool 57 // Quiet silences warnings. 58 Quiet bool 59 // Concurrency defines the parsing concurrency. 60 Concurrency ParseManifestConcurrency 61 } 62 63 // ParseManifest parses a manifest file (i.e. build.ninja). 64 // 65 // The input must contain a trailing terminating zero byte. 66 func ParseManifest(state *State, fr FileReader, options ParseManifestOpts, filename string, input []byte) error { 67 if options.Concurrency != ParseManifestConcurrentParsing { 68 m := manifestParserSerial{ 69 fr: fr, 70 options: options, 71 state: state, 72 env: state.Bindings, 73 } 74 return m.parse(filename, input) 75 } 76 m := manifestParserConcurrent{ 77 manifestParserRoutine: manifestParserRoutine{ 78 manifestParserContext: manifestParserContext{ 79 env: state.Bindings, 80 doneParsing: barrier{ 81 want: make(chan struct{}), 82 }, 83 }, 84 }, 85 manifestParserState: manifestParserState{ 86 state: state, 87 options: options, 88 fr: fr, 89 }, 90 } 91 return m.parseMain(filename, input) 92 } 93 94 // subninja is a struct used to manage parallel reading of subninja files. 95 type subninja struct { 96 filename string 97 input []byte 98 err error 99 ls lexerState // lexer state when the subninja statement was parsed. 100 env *BindingEnv 101 } 102 103 // readSubninjaAsync is the goroutine that reads the subninja file in parallel 104 // to the main build.ninja to reduce overall latency. 105 func readSubninjaAsync(fr FileReader, filename string, ch chan<- subninja, ls lexerState, env *BindingEnv) { 106 input, err := fr.ReadFile(filename) 107 ch <- subninja{ 108 filename: filename, 109 input: input, 110 err: err, 111 ls: ls, 112 env: env, 113 } 114 }