1// Copyright 2015 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 15package cc 16 17import ( 18 "path/filepath" 19 "strings" 20 21 "github.com/google/blueprint" 22 23 "android/soong/android" 24) 25 26func init() { 27 pctx.SourcePathVariable("lexCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/flex") 28 pctx.SourcePathVariable("m4Cmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/m4") 29 30 pctx.HostBinToolVariable("aidlCmd", "aidl-cpp") 31 pctx.HostBinToolVariable("syspropCmd", "sysprop_cpp") 32} 33 34var ( 35 lex = pctx.AndroidStaticRule("lex", 36 blueprint.RuleParams{ 37 Command: "M4=$m4Cmd $lexCmd $flags -o$out $in", 38 CommandDeps: []string{"$lexCmd", "$m4Cmd"}, 39 }, "flags") 40 41 sysprop = pctx.AndroidStaticRule("sysprop", 42 blueprint.RuleParams{ 43 Command: "$syspropCmd --header-dir=$headerOutDir --public-header-dir=$publicOutDir " + 44 "--source-dir=$srcOutDir --include-name=$includeName $in", 45 CommandDeps: []string{"$syspropCmd"}, 46 }, 47 "headerOutDir", "publicOutDir", "srcOutDir", "includeName") 48 49 windmc = pctx.AndroidStaticRule("windmc", 50 blueprint.RuleParams{ 51 Command: "$windmcCmd -r$$(dirname $out) -h$$(dirname $out) $in", 52 CommandDeps: []string{"$windmcCmd"}, 53 }, 54 "windmcCmd") 55) 56 57type YaccProperties struct { 58 // list of module-specific flags that will be used for .y and .yy compiles 59 Flags []string 60 61 // whether the yacc files will produce a location.hh file 62 Gen_location_hh *bool 63 64 // whether the yacc files will product a position.hh file 65 Gen_position_hh *bool 66} 67 68func genYacc(ctx android.ModuleContext, rule *android.RuleBuilder, yaccFile android.Path, 69 outFile android.ModuleGenPath, props *YaccProperties) (headerFiles android.Paths) { 70 71 outDir := android.PathForModuleGen(ctx, "yacc") 72 headerFile := android.GenPathWithExt(ctx, "yacc", yaccFile, "h") 73 ret := android.Paths{headerFile} 74 75 cmd := rule.Command() 76 77 // Fix up #line markers to not use the sbox temporary directory 78 // android.sboxPathForOutput(outDir, outDir) returns the sbox placeholder for the out 79 // directory itself, without any filename appended. 80 sboxOutDir := cmd.PathForOutput(outDir) 81 sedCmd := "sed -i.bak 's#" + sboxOutDir + "#" + outDir.String() + "#'" 82 rule.Command().Text(sedCmd).Input(outFile) 83 rule.Command().Text(sedCmd).Input(headerFile) 84 85 var flags []string 86 if props != nil { 87 flags = props.Flags 88 89 if Bool(props.Gen_location_hh) { 90 locationHeader := outFile.InSameDir(ctx, "location.hh") 91 ret = append(ret, locationHeader) 92 cmd.ImplicitOutput(locationHeader) 93 rule.Command().Text(sedCmd).Input(locationHeader) 94 } 95 if Bool(props.Gen_position_hh) { 96 positionHeader := outFile.InSameDir(ctx, "position.hh") 97 ret = append(ret, positionHeader) 98 cmd.ImplicitOutput(positionHeader) 99 rule.Command().Text(sedCmd).Input(positionHeader) 100 } 101 } 102 103 cmd.Text("BISON_PKGDATADIR=prebuilts/build-tools/common/bison"). 104 FlagWithInput("M4=", ctx.Config().PrebuiltBuildTool(ctx, "m4")). 105 PrebuiltBuildTool(ctx, "bison"). 106 Flag("-d"). 107 Flags(flags). 108 FlagWithOutput("--defines=", headerFile). 109 Flag("-o").Output(outFile).Input(yaccFile) 110 111 return ret 112} 113 114func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile android.Path, aidlFlags string) (cppFile android.OutputPath, headerFiles android.Paths) { 115 aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base()) 116 baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext()) 117 shortName := baseName 118 // TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if 119 // an interface name has a leading I. Those same heuristics have been 120 // moved here. 121 if len(baseName) >= 2 && baseName[0] == 'I' && 122 strings.ToUpper(baseName)[1] == baseName[1] { 123 shortName = strings.TrimPrefix(baseName, "I") 124 } 125 126 outDir := android.PathForModuleGen(ctx, "aidl") 127 cppFile = outDir.Join(ctx, aidlPackage, baseName+".cpp") 128 depFile := outDir.Join(ctx, aidlPackage, baseName+".cpp.d") 129 headerI := outDir.Join(ctx, aidlPackage, baseName+".h") 130 headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h") 131 headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h") 132 133 baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel()) 134 if baseDir != "" { 135 aidlFlags += " -I" + baseDir 136 } 137 138 cmd := rule.Command() 139 cmd.BuiltTool("aidl-cpp"). 140 FlagWithDepFile("-d", depFile). 141 Flag("--ninja"). 142 Flag(aidlFlags). 143 Input(aidlFile). 144 OutputDir(). 145 Output(cppFile). 146 ImplicitOutputs(android.WritablePaths{ 147 headerI, 148 headerBn, 149 headerBp, 150 }) 151 152 return cppFile, android.Paths{ 153 headerI, 154 headerBn, 155 headerBp, 156 } 157} 158 159type LexProperties struct { 160 // list of module-specific flags that will be used for .l and .ll compiles 161 Flags []string 162} 163 164func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath, props *LexProperties) { 165 var flags []string 166 if props != nil { 167 flags = props.Flags 168 } 169 flagsString := strings.Join(flags[:], " ") 170 ctx.Build(pctx, android.BuildParams{ 171 Rule: lex, 172 Description: "lex " + lexFile.Rel(), 173 Output: outFile, 174 Input: lexFile, 175 Args: map[string]string{"flags": flagsString}, 176 }) 177} 178 179func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) { 180 headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h") 181 publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h") 182 cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp") 183 184 headers := android.WritablePaths{headerFile, publicHeaderFile} 185 186 ctx.Build(pctx, android.BuildParams{ 187 Rule: sysprop, 188 Description: "sysprop " + syspropFile.Rel(), 189 Output: cppFile, 190 ImplicitOutputs: headers, 191 Input: syspropFile, 192 Args: map[string]string{ 193 "headerOutDir": filepath.Dir(headerFile.String()), 194 "publicOutDir": filepath.Dir(publicHeaderFile.String()), 195 "srcOutDir": filepath.Dir(cppFile.String()), 196 "includeName": syspropFile.Rel() + ".h", 197 }, 198 }) 199 200 return cppFile, headers.Paths() 201} 202 203func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFlags) (android.Path, android.Path) { 204 headerFile := android.GenPathWithExt(ctx, "windmc", srcFile, "h") 205 rcFile := android.GenPathWithExt(ctx, "windmc", srcFile, "rc") 206 207 windmcCmd := gccCmd(flags.toolchain, "windmc") 208 209 ctx.Build(pctx, android.BuildParams{ 210 Rule: windmc, 211 Description: "windmc " + srcFile.Rel(), 212 Output: rcFile, 213 ImplicitOutput: headerFile, 214 Input: srcFile, 215 Args: map[string]string{ 216 "windmcCmd": windmcCmd, 217 }, 218 }) 219 220 return rcFile, headerFile 221} 222 223// Used to communicate information from the genSources method back to the library code that uses 224// it. 225type generatedSourceInfo struct { 226 // The headers created from .proto files 227 protoHeaders android.Paths 228 229 // The files that can be used as order only dependencies in order to ensure that the proto header 230 // files are up to date. 231 protoOrderOnlyDeps android.Paths 232 233 // The headers created from .aidl files 234 aidlHeaders android.Paths 235 236 // The files that can be used as order only dependencies in order to ensure that the aidl header 237 // files are up to date. 238 aidlOrderOnlyDeps android.Paths 239 240 // The headers created from .sysprop files 241 syspropHeaders android.Paths 242 243 // The files that can be used as order only dependencies in order to ensure that the sysprop 244 // header files are up to date. 245 syspropOrderOnlyDeps android.Paths 246} 247 248func genSources(ctx android.ModuleContext, srcFiles android.Paths, 249 buildFlags builderFlags) (android.Paths, android.Paths, generatedSourceInfo) { 250 251 var info generatedSourceInfo 252 253 var deps android.Paths 254 var rsFiles android.Paths 255 256 var aidlRule *android.RuleBuilder 257 258 var yaccRule_ *android.RuleBuilder 259 yaccRule := func() *android.RuleBuilder { 260 if yaccRule_ == nil { 261 yaccRule_ = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "yacc"), 262 android.PathForModuleGen(ctx, "yacc.sbox.textproto")) 263 } 264 return yaccRule_ 265 } 266 267 for i, srcFile := range srcFiles { 268 switch srcFile.Ext() { 269 case ".y": 270 cFile := android.GenPathWithExt(ctx, "yacc", srcFile, "c") 271 srcFiles[i] = cFile 272 deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cFile, buildFlags.yacc)...) 273 case ".yy": 274 cppFile := android.GenPathWithExt(ctx, "yacc", srcFile, "cpp") 275 srcFiles[i] = cppFile 276 deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cppFile, buildFlags.yacc)...) 277 case ".l": 278 cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c") 279 srcFiles[i] = cFile 280 genLex(ctx, srcFile, cFile, buildFlags.lex) 281 case ".ll": 282 cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp") 283 srcFiles[i] = cppFile 284 genLex(ctx, srcFile, cppFile, buildFlags.lex) 285 case ".proto": 286 ccFile, headerFile := genProto(ctx, srcFile, buildFlags) 287 srcFiles[i] = ccFile 288 info.protoHeaders = append(info.protoHeaders, headerFile) 289 // Use the generated header as an order only dep to ensure that it is up to date when needed. 290 info.protoOrderOnlyDeps = append(info.protoOrderOnlyDeps, headerFile) 291 case ".aidl": 292 if aidlRule == nil { 293 aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"), 294 android.PathForModuleGen(ctx, "aidl.sbox.textproto")) 295 } 296 cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags) 297 srcFiles[i] = cppFile 298 299 info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...) 300 // Use the generated headers as order only deps to ensure that they are up to date when 301 // needed. 302 // TODO: Reduce the size of the ninja file by using one order only dep for the whole rule 303 info.aidlOrderOnlyDeps = append(info.aidlOrderOnlyDeps, aidlHeaders...) 304 case ".rscript", ".fs": 305 cppFile := rsGeneratedCppFile(ctx, srcFile) 306 rsFiles = append(rsFiles, srcFiles[i]) 307 srcFiles[i] = cppFile 308 case ".mc": 309 rcFile, headerFile := genWinMsg(ctx, srcFile, buildFlags) 310 srcFiles[i] = rcFile 311 deps = append(deps, headerFile) 312 case ".sysprop": 313 cppFile, headerFiles := genSysprop(ctx, srcFile) 314 srcFiles[i] = cppFile 315 info.syspropHeaders = append(info.syspropHeaders, headerFiles...) 316 // Use the generated headers as order only deps to ensure that they are up to date when 317 // needed. 318 info.syspropOrderOnlyDeps = append(info.syspropOrderOnlyDeps, headerFiles...) 319 } 320 } 321 322 if aidlRule != nil { 323 aidlRule.Build("aidl", "gen aidl") 324 } 325 326 if yaccRule_ != nil { 327 yaccRule_.Build("yacc", "gen yacc") 328 } 329 330 deps = append(deps, info.protoOrderOnlyDeps...) 331 deps = append(deps, info.aidlOrderOnlyDeps...) 332 deps = append(deps, info.syspropOrderOnlyDeps...) 333 334 if len(rsFiles) > 0 { 335 deps = append(deps, rsGenerateCpp(ctx, rsFiles, buildFlags.rsFlags)...) 336 } 337 338 return srcFiles, deps, info 339} 340