blob: 60b320d11139df8e597728b3917b738125f4af5c [file] [log] [blame]
// Copyright 2019 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 (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"fidl/compiler/backend/types"
)
// flagsDef defines the LLCPP flags schema.
type flagsDef struct {
jsonPath *string
header *string
source *string
includeBase *string
}
var flags = func() flagsDef {
return flagsDef{
jsonPath: flag.String("json", "",
"relative path to the FIDL intermediate representation."),
header: flag.String("header", "",
"the output path for the generated header."),
source: flag.String("source", "",
"the output path for the generated C++ implementation."),
includeBase: flag.String("include-base", "",
"[optional] the directory relative to which includes will be computed. " +
"If omitted, assumes #include <fidl/library/name/llcpp/fidl.h>"),
}
}()
// valid returns true if the parsed flags are valid.
func (f flagsDef) valid() bool {
return *f.jsonPath != "" && *f.header != "" && *f.source != ""
}
type config struct {
fidl types.Root
headerPath string
sourcePath string
primaryHeaderPath string
}
// decodeTypes decodes FIDL type information from the JSON file specified as an argument.
func decodeTypes(jsonPath string) (types.Root, error) {
bytes, err := ioutil.ReadFile(jsonPath)
if err != nil {
return types.Root{}, fmt.Errorf("error reading from %s: %v", jsonPath, err)
}
var fidl types.Root
err = json.Unmarshal(bytes, &fidl)
if err != nil {
return types.Root{}, fmt.Errorf("error parsing JSON as FIDL data: %v", err)
}
for _, l := range fidl.Libraries {
for k, v := range l.Decls {
fidl.Decls[types.EnsureLibrary(l.Name, k)] = v
}
}
return fidl, nil
}
func (f flagsDef) getConfig() (config, error) {
fidl, err := decodeTypes(*f.jsonPath)
headerPath, err := filepath.Abs(*f.header)
if err != nil {
return config{}, err
}
sourcePath, err := filepath.Abs(*f.source)
if err != nil {
return config{}, err
}
var primaryHeaderPath string
if *f.includeBase != "" {
absoluteIncludeBase, err := filepath.Abs(*f.includeBase)
if err != nil {
return config{}, err
}
if !strings.HasPrefix(headerPath, absoluteIncludeBase) {
return config{}, fmt.Errorf("include-base (%v) is not a parent of header (%v)", absoluteIncludeBase, headerPath)
}
relStem, err := filepath.Rel(*f.includeBase, *f.header)
if err != nil {
return config{}, err
}
primaryHeaderPath = relStem
} else {
// Assume the convention for including fidl library dependencies, i.e.
// #include <fuchsia/library/name/llcpp/fidl.h>
var parts []string
for _, part := range fidl.Name.Parts() {
parts = append(parts, string(part))
}
parts = append(parts, "llcpp", "fidl.h")
primaryHeaderPath = filepath.Join(parts...)
}
return config{
fidl: fidl,
headerPath: headerPath,
sourcePath: sourcePath,
primaryHeaderPath: primaryHeaderPath,
}, nil
}
func main() {
flag.Parse()
if !flag.Parsed() || !flags.valid() {
flag.PrintDefaults()
os.Exit(1)
}
config, err := flags.getConfig()
if err != nil {
log.Fatalf("Error getting config: %v", err)
}
generator := newGenerator()
err = generator.generateFidl(config)
if err != nil {
log.Fatalf("Error running generator: %v", err)
}
}