1// Copyright 2018 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 xsdc 16 17import ( 18 "path/filepath" 19 "strings" 20 21 "android/soong/android" 22 "android/soong/java" 23 24 "github.com/google/blueprint" 25 "github.com/google/blueprint/proptools" 26) 27 28func init() { 29 pctx.Import("android/soong/java/config") 30 android.RegisterModuleType("xsd_config", xsdConfigFactory) 31 32 android.PreArchMutators(func(ctx android.RegisterMutatorsContext) { 33 ctx.TopDown("xsd_config", xsdConfigMutator).Parallel() 34 }) 35} 36 37var ( 38 pctx = android.NewPackageContext("android/xsdc") 39 40 xsdc = pctx.HostBinToolVariable("xsdcCmd", "xsdc") 41 42 xsdConfigRule = pctx.StaticRule("xsdConfigRule", blueprint.RuleParams{ 43 Command: "cp -f ${in} ${output}", 44 Description: "copy the xsd file: ${in} => ${output}", 45 }, "output") 46) 47 48type xsdConfigProperties struct { 49 Srcs []string 50 Package_name *string 51 Api_dir *string 52 Gen_writer *bool 53 Nullability *bool 54 55 // Whether has{element or atrribute} methods are set to public. 56 // It is not applied to C++, because these methods are always 57 // generated to public for C++. 58 Gen_has *bool 59 // Only generate code for enum converters. Applies to C++ only. 60 // This is useful for memory footprint reduction since it avoids 61 // depending on libxml2. 62 Enums_only *bool 63 // Only generate complementary code for XML parser. Applies to C++ only. 64 // The code being generated depends on the enum converters module. 65 Parser_only *bool 66 // Whether getter name of boolean element or attribute is getX or isX. 67 // Default value is false. If the property is true, getter name is isX. 68 Boolean_getter *bool 69 // Generate code that uses libtinyxml2 instead of libxml2. Applies to 70 // C++ only and does not perform the XInclude substitution, or 71 // ENTITY_REFs. 72 // This can improve memory footprint. Default value is false. 73 Tinyxml *bool 74 // Specify root elements explicitly. If not set, XSDC generates parsers and 75 // writers for all elements which can be root element. When set, XSDC 76 // generates parsers and writers for specified root elements. This can be 77 // used to avoid unnecessary code. 78 Root_elements []string 79 // Additional xsd files included by the main xsd file using xs:include 80 // The paths are relative to the module directory. 81 Include_files []string 82} 83 84type xsdConfig struct { 85 android.ModuleBase 86 87 properties xsdConfigProperties 88 89 genOutputDir android.Path 90 genOutputs_j android.WritablePath 91 genOutputs_c android.WritablePaths 92 genOutputs_h android.WritablePaths 93 94 docsPath android.Path 95 96 xsdConfigPath android.Path 97 xsdIncludeConfigPaths android.Paths 98 genOutputs android.WritablePaths 99} 100 101var _ android.SourceFileProducer = (*xsdConfig)(nil) 102 103type ApiToCheck struct { 104 Api_file *string 105 Removed_api_file *string 106 Args *string 107} 108 109type CheckApi struct { 110 Last_released ApiToCheck 111 Current ApiToCheck 112} 113type DroidstubsProperties struct { 114 Name *string 115 Installable *bool 116 Srcs []string 117 Sdk_version *string 118 Args *string 119 Api_filename *string 120 Removed_api_filename *string 121 Check_api CheckApi 122} 123 124func (module *xsdConfig) GeneratedSourceFiles() android.Paths { 125 return module.genOutputs_c.Paths() 126} 127 128func (module *xsdConfig) Srcs() android.Paths { 129 var srcs android.WritablePaths 130 srcs = append(srcs, module.genOutputs...) 131 srcs = append(srcs, module.genOutputs_j) 132 return srcs.Paths() 133} 134 135func (module *xsdConfig) GeneratedDeps() android.Paths { 136 return module.genOutputs_h.Paths() 137} 138 139func (module *xsdConfig) GeneratedHeaderDirs() android.Paths { 140 return android.Paths{module.genOutputDir} 141} 142 143func (module *xsdConfig) DepsMutator(ctx android.BottomUpMutatorContext) { 144 android.ExtractSourcesDeps(ctx, module.properties.Srcs) 145} 146 147func (module *xsdConfig) generateXsdConfig(ctx android.ModuleContext) { 148 output := android.PathForModuleGen(ctx, module.Name()+".xsd") 149 module.genOutputs = append(module.genOutputs, output) 150 151 ctx.ModuleBuild(pctx, android.ModuleBuildParams{ 152 Rule: xsdConfigRule, 153 Input: module.xsdConfigPath, 154 Output: output, 155 Args: map[string]string{ 156 "output": output.String(), 157 }, 158 }) 159} 160 161// This creates a ninja rule to convert xsd file to java sources 162// The ninja rule runs in a sandbox 163func (module *xsdConfig) generateJavaSrcInSbox(ctx android.ModuleContext, args string) { 164 rule := android.NewRuleBuilder(pctx, ctx). 165 Sbox(android.PathForModuleGen(ctx, "java"), 166 android.PathForModuleGen(ctx, "java.sbox.textproto")). 167 SandboxInputs() 168 // Run xsdc tool to generate sources 169 genCmd := rule.Command() 170 genCmd. 171 BuiltTool("xsdc"). 172 ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "xsdc.jar")). 173 Input(module.xsdConfigPath). 174 FlagWithArg("-p ", *module.properties.Package_name). 175 // Soong will change execution root to sandbox root. Generate srcs relative to that. 176 Flag("-o ").OutputDir("xsdc"). 177 FlagWithArg("-j ", args) 178 if module.xsdIncludeConfigPaths != nil { 179 genCmd.Implicits(module.xsdIncludeConfigPaths) 180 } 181 if module.docsPath != nil { 182 genCmd.Implicit(module.docsPath) 183 } 184 // Zip the source file to a srcjar 185 rule.Command(). 186 BuiltTool("soong_zip"). 187 Flag("-jar"). 188 FlagWithOutput("-o ", module.genOutputs_j). 189 Flag("-C ").OutputDir("xsdc"). 190 Flag("-D ").OutputDir("xsdc") 191 192 rule.Build("xsdc_java_"+module.xsdConfigPath.String(), "xsdc java") 193} 194 195// This creates a ninja rule to convert xsd file to cpp sources 196// The ninja rule runs in a sandbox 197func (module *xsdConfig) generateCppSrcInSbox(ctx android.ModuleContext, args string) { 198 outDir := android.PathForModuleGen(ctx, "cpp") 199 rule := android.NewRuleBuilder(pctx, ctx). 200 Sbox(outDir, 201 android.PathForModuleGen(ctx, "cpp.sbox.textproto")). 202 SandboxInputs() 203 // Run xsdc tool to generate sources 204 genCmd := rule.Command() 205 genCmd. 206 BuiltTool("xsdc"). 207 ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "xsdc.jar")). 208 Input(module.xsdConfigPath). 209 FlagWithArg("-p ", *module.properties.Package_name). 210 // Soong will change execution root to sandbox root. Generate srcs relative to that. 211 Flag("-o ").OutputDir(). 212 FlagWithArg("-c ", args). 213 ImplicitOutputs(module.genOutputs_c). 214 ImplicitOutputs(module.genOutputs_h) 215 if module.xsdIncludeConfigPaths != nil { 216 genCmd.Implicits(module.xsdIncludeConfigPaths) 217 } 218 219 rule.Build("xsdc_cpp_"+module.xsdConfigPath.String(), "xsdc cpp") 220} 221 222func (module *xsdConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { 223 if len(module.properties.Srcs) != 1 { 224 ctx.PropertyErrorf("srcs", "xsd_config must be one src") 225 } 226 227 ctx.VisitDirectDeps(func(to android.Module) { 228 if doc, ok := to.(java.ApiFilePath); ok { 229 docsPath, err := doc.ApiFilePath(java.Everything) 230 if err != nil { 231 ctx.ModuleErrorf(err.Error()) 232 } else { 233 module.docsPath = docsPath 234 } 235 } 236 }) 237 238 srcFiles := ctx.ExpandSources(module.properties.Srcs, nil) 239 module.xsdConfigPath = srcFiles[0] 240 module.xsdIncludeConfigPaths = android.PathsForModuleSrc(ctx, module.properties.Include_files) 241 242 pkgName := *module.properties.Package_name 243 filenameStem := strings.Replace(pkgName, ".", "_", -1) 244 245 args := "" 246 if proptools.Bool(module.properties.Gen_writer) { 247 args = "-w" 248 } 249 250 if proptools.Bool(module.properties.Nullability) { 251 args = args + " -n " 252 } 253 254 if proptools.Bool(module.properties.Gen_has) { 255 args = args + " -g " 256 } 257 258 if proptools.Bool(module.properties.Enums_only) { 259 args = args + " -e " 260 } 261 262 if proptools.Bool(module.properties.Parser_only) { 263 args = args + " -x " 264 } 265 266 if proptools.Bool(module.properties.Boolean_getter) { 267 args = args + " -b " 268 } 269 270 if proptools.Bool(module.properties.Tinyxml) { 271 args = args + " -t " 272 } 273 274 for _, elem := range module.properties.Root_elements { 275 args = args + " -r " + elem 276 } 277 278 module.genOutputs_j = android.PathForModuleGen(ctx, "java", filenameStem+"_xsdcgen.srcjar") 279 280 module.generateJavaSrcInSbox(ctx, args) 281 282 if proptools.Bool(module.properties.Enums_only) { 283 module.genOutputs_c = android.WritablePaths{ 284 android.PathForModuleGen(ctx, "cpp", filenameStem+"_enums.cpp")} 285 module.genOutputs_h = android.WritablePaths{ 286 android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+"_enums.h")} 287 } else if proptools.Bool(module.properties.Parser_only) { 288 module.genOutputs_c = android.WritablePaths{ 289 android.PathForModuleGen(ctx, "cpp", filenameStem+".cpp")} 290 module.genOutputs_h = android.WritablePaths{ 291 android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h")} 292 } else { 293 module.genOutputs_c = android.WritablePaths{ 294 android.PathForModuleGen(ctx, "cpp", filenameStem+".cpp"), 295 android.PathForModuleGen(ctx, "cpp", filenameStem+"_enums.cpp")} 296 module.genOutputs_h = android.WritablePaths{ 297 android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+".h"), 298 android.PathForModuleGen(ctx, "cpp", "include/"+filenameStem+"_enums.h")} 299 } 300 301 module.genOutputDir = android.PathForModuleGen(ctx, "cpp", "include") 302 303 module.generateCppSrcInSbox(ctx, args) 304 305 module.generateXsdConfig(ctx) 306 307 module.setOutputFiles(ctx) 308} 309 310func (module *xsdConfig) setOutputFiles(ctx android.ModuleContext) { 311 var defaultOutputFiles android.WritablePaths 312 defaultOutputFiles = append(defaultOutputFiles, module.genOutputs_j) 313 defaultOutputFiles = append(defaultOutputFiles, module.genOutputs_c...) 314 defaultOutputFiles = append(defaultOutputFiles, module.genOutputs_h...) 315 defaultOutputFiles = append(defaultOutputFiles, module.genOutputs...) 316 ctx.SetOutputFiles(defaultOutputFiles.Paths(), "") 317 ctx.SetOutputFiles(android.Paths{module.genOutputs_j}, "java") 318 ctx.SetOutputFiles(module.genOutputs_c.Paths(), "cpp") 319 ctx.SetOutputFiles(module.genOutputs_h.Paths(), "h") 320} 321 322func xsdConfigMutator(mctx android.TopDownMutatorContext) { 323 if module, ok := mctx.Module().(*xsdConfig); ok { 324 name := module.BaseModuleName() 325 326 args := " --stub-packages " + *module.properties.Package_name + 327 " --hide MissingPermission --hide BroadcastBehavior" + 328 " --hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol" + 329 " --hide SdkConstant --hide HiddenTypeParameter --hide Todo" 330 331 api_dir := proptools.StringDefault(module.properties.Api_dir, "api") 332 333 currentApiFileName := filepath.Join(api_dir, "current.txt") 334 removedApiFileName := filepath.Join(api_dir, "removed.txt") 335 336 check_api := CheckApi{} 337 338 check_api.Current.Api_file = proptools.StringPtr(currentApiFileName) 339 check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName) 340 341 check_api.Last_released.Api_file = proptools.StringPtr( 342 filepath.Join(api_dir, "last_current.txt")) 343 check_api.Last_released.Removed_api_file = proptools.StringPtr( 344 filepath.Join(api_dir, "last_removed.txt")) 345 346 mctx.CreateModule(java.DroidstubsFactory, &DroidstubsProperties{ 347 Name: proptools.StringPtr(name + ".docs"), 348 Srcs: []string{":" + name}, 349 Args: proptools.StringPtr(args), 350 Api_filename: proptools.StringPtr(currentApiFileName), 351 Removed_api_filename: proptools.StringPtr(removedApiFileName), 352 Check_api: check_api, 353 Installable: proptools.BoolPtr(false), 354 Sdk_version: proptools.StringPtr("core_platform"), 355 }) 356 } 357} 358 359func xsdConfigFactory() android.Module { 360 module := &xsdConfig{} 361 module.AddProperties(&module.properties) 362 android.InitAndroidModule(module) 363 364 return module 365} 366