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