| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package main |
| |
| import ( |
| "flag" |
| "fmt" |
| "log" |
| "os" |
| |
| "go.fuchsia.dev/fuchsia/tools/fidl/fidlgen_hlcpp/codegen" |
| "go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen" |
| cpp "go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen_cpp" |
| ) |
| |
| type flagsDef struct { |
| cpp.CommonFlags |
| |
| // Note: this option is not exercised in-tree. |
| // Whenever changing the handling for outputBase, some SDK presubmit testing |
| // is encouraged. |
| outputBase *string |
| |
| testBase *string |
| |
| // TODO(fxbug.dev/45483): Until all SDK consumers are moved off to using dedicated |
| // flags to invoke HLCPP fidlgen, we must preserve this legacy flag. |
| generatorsUnused *string |
| |
| // If true, only generate the domain objects. |
| splitGenerationDomainObjects *bool |
| } |
| |
| var flags = flagsDef{ |
| CommonFlags: cpp.CommonFlags{ |
| Json: flag.String("json", "", |
| "relative path to the FIDL intermediate representation."), |
| Header: flag.String("header", "", |
| "the output path for the generated header. "+ |
| "It cannot be supplied together with outputBase."), |
| Source: flag.String("source", "", |
| "the output path for the generated C++ implementation. "+ |
| "It cannot be supplied together with outputBase."), |
| IncludeBase: flag.String("include-base", "", |
| "the directory to which C and C++ includes should be relative."), |
| IncludeStem: flag.String("include-stem", "cpp/fidl", |
| "[optional] the suffix after library path when referencing includes. "+ |
| "Includes will be of the form <my/library/{include-stem}.h>. "), |
| ClangFormatPath: flag.String("clang-format-path", "", |
| "path to the clang-format tool."), |
| }, |
| outputBase: flag.String("output-base", "", |
| "the base file name for files generated by this generator. "+ |
| "It cannot be supplied together with header/source/test-base."), |
| testBase: flag.String("test-base", "", |
| "the output path for the generated test base header. "+ |
| "It cannot be supplied together with outputBase."), |
| generatorsUnused: flag.String("generators", "", |
| "unused"), |
| splitGenerationDomainObjects: flag.Bool("experimental-split-generation-domain-objects", false, |
| "[optional] only generate the domain object definitions for the data types in this library."), |
| } |
| |
| // intoOptions validates the incoming flags and computes the generated file paths |
| // from a valid flag combination. |
| func (f flagsDef) intoOptions() (codegenOptions, error) { |
| if *f.Json == "" { |
| return codegenOptions{}, fmt.Errorf("-json is required") |
| } |
| if *f.IncludeBase == "" { |
| return codegenOptions{}, fmt.Errorf("-include-base is required") |
| } |
| mode := codegen.Monolithic |
| if *flags.splitGenerationDomainObjects { |
| mode = codegen.OnlyGenerateDomainObjects |
| } |
| if *f.splitGenerationDomainObjects && *f.testBase != "" { |
| return codegenOptions{}, fmt.Errorf("there is no test base header when generating only the " + |
| "domain objects") |
| } |
| if *f.outputBase == "" { |
| if *f.Header == "" || *f.Source == "" || |
| (*f.testBase == "" && !*f.splitGenerationDomainObjects) { |
| return codegenOptions{}, fmt.Errorf("must specify either -output-base, or all of " + |
| "-header, -source, -test-base, unless -experimental-split-generation-domain-objects " + |
| "is specified in which case -test-base must be omitted") |
| } |
| return codegenOptions{ |
| jsonPath: *f.Json, |
| header: *f.Header, |
| source: *f.Source, |
| testBase: *f.testBase, |
| includeBase: *f.IncludeBase, |
| includeStem: *f.IncludeStem, |
| mode: mode, |
| }, nil |
| } else { |
| if *f.Header != "" || *f.Source != "" || *f.testBase != "" { |
| return codegenOptions{}, fmt.Errorf("cannot specify both -output-base, and any of " + |
| "-header, -source, -test-base") |
| } |
| var testBase string |
| if !*f.splitGenerationDomainObjects { |
| testBase = *f.outputBase + "_test_base.h" |
| } |
| return codegenOptions{ |
| jsonPath: *f.Json, |
| header: *f.outputBase + ".h", |
| source: *f.outputBase + ".cc", |
| testBase: testBase, |
| includeBase: *f.IncludeBase, |
| includeStem: *f.IncludeStem, |
| mode: mode, |
| }, nil |
| } |
| } |
| |
| // codegenOptions is a processed version of flagsDef. In particular, it resolves |
| // `-output-base` into header/source file paths, if that option was specified. |
| type codegenOptions struct { |
| jsonPath string |
| header string |
| source string |
| testBase string |
| includeBase string |
| includeStem string |
| mode codegen.CodeGenerationMode |
| } |
| |
| var _ cpp.CodegenOptions = (*codegenOptions)(nil) |
| var _ codegen.Config = (*codegenOptions)(nil) |
| |
| func (c codegenOptions) Header() string { |
| return c.header |
| } |
| |
| func (c codegenOptions) Source() string { |
| return c.source |
| } |
| |
| func (c codegenOptions) HasTestBase() bool { |
| return c.testBase != "" |
| } |
| |
| func (c codegenOptions) TestBase() string { |
| if !c.HasTestBase() { |
| panic("Missing test base") |
| } |
| return c.testBase |
| } |
| |
| func (c codegenOptions) IncludeBase() string { |
| return c.includeBase |
| } |
| |
| func (c codegenOptions) IncludeStem() string { |
| return c.includeStem |
| } |
| |
| func main() { |
| flag.Parse() |
| if !flag.Parsed() { |
| flag.PrintDefaults() |
| os.Exit(1) |
| } |
| |
| opts, err := flags.intoOptions() |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| ir, err := fidlgen.ReadJSONIr(opts.jsonPath) |
| if err != nil { |
| log.Fatal(err) |
| } |
| |
| generator := codegen.NewFidlGenerator(opts.mode) |
| if err := generator.GenerateFidl(ir, opts, *flags.ClangFormatPath); err != nil { |
| log.Fatalf("Error running generator: %v", err) |
| } |
| } |