blob: c92a8bbf7f5400ad172a451749ed7580805a1c63 [file] [log] [blame]
// 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)
}
}