111 lines
2.9 KiB
Go
111 lines
2.9 KiB
Go
// Copyright 2022 Google LLC
|
|
//
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package exporter
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"go.skia.org/infra/go/skerr"
|
|
"go.skia.org/infra/go/util"
|
|
"go.skia.org/skia/bazel/exporter/build_proto/build"
|
|
)
|
|
|
|
// cmakeWorkspace represents the entire state of a CMake project.
|
|
type cmakeWorkspace struct {
|
|
// Map Bazel rule names to cmakeRule instances. Holding pointer
|
|
// values as the rules are mutable.
|
|
rules map[string]*cmakeRule
|
|
}
|
|
|
|
// writeState tracks the state of an in-progress write of the workspace.
|
|
type writeState struct {
|
|
writtenRules []string // All cmakeRule's written during write.
|
|
}
|
|
|
|
// newCMakeWorkspace will create a new CMake workspace object.
|
|
func newCMakeWorkspace() *cmakeWorkspace {
|
|
return &cmakeWorkspace{rules: map[string]*cmakeRule{}}
|
|
}
|
|
|
|
// Determine if a rule has been written.
|
|
func (s *writeState) isRuleWritten(ruleName string) bool {
|
|
return util.In(ruleName, s.writtenRules)
|
|
}
|
|
|
|
// setRuleWritten will mark the rule as having been written.
|
|
func (s *writeState) setRuleWritten(ruleName string) {
|
|
s.writtenRules = append(s.writtenRules, ruleName)
|
|
}
|
|
|
|
// getRule will return the CMake wrapper for a Bazel rule given the
|
|
// rule name. Will return nil if there is no corresponding rule.
|
|
func (w *cmakeWorkspace) getRule(name string) *cmakeRule {
|
|
return w.rules[name]
|
|
}
|
|
|
|
// createRule will create (if necessary) a new CMake rule object
|
|
// for the given rule name.
|
|
func (w *cmakeWorkspace) createRule(rule *build.Rule) *cmakeRule {
|
|
if r := w.getRule(rule.GetName()); r != nil {
|
|
return r
|
|
}
|
|
r := newCMakeRule(rule)
|
|
w.rules[rule.GetName()] = r
|
|
return r
|
|
}
|
|
|
|
// writeRule will write the given rule to the writer.
|
|
// It will first write all dependent rules so that they appear
|
|
// in the CMake project file before the rule that depends on them.
|
|
func (w *cmakeWorkspace) writeRule(writer io.Writer, r *cmakeRule, state *writeState) (int, error) {
|
|
nb := 0
|
|
if !r.hasSrcs() {
|
|
return 0, nil
|
|
}
|
|
// First write all dependencies because CMake does not support forward references.
|
|
for _, name := range r.deps {
|
|
dep := w.getRule(name)
|
|
if dep == nil {
|
|
return 0, skerr.Fmt(`cannot find rule %q`, name)
|
|
}
|
|
n, err := w.writeRule(writer, dep, state)
|
|
if err != nil {
|
|
return nb, skerr.Wrap(err)
|
|
}
|
|
nb += n
|
|
}
|
|
if state.isRuleWritten(r.getName()) {
|
|
return nb, nil
|
|
}
|
|
num, err := fmt.Fprintln(writer)
|
|
if err != nil {
|
|
return nb, skerr.Wrap(err)
|
|
}
|
|
nb += num
|
|
num, err = r.write(writer)
|
|
if err != nil {
|
|
return nb, skerr.Wrap(err)
|
|
}
|
|
state.setRuleWritten(r.getName())
|
|
nb += num
|
|
return nb, nil
|
|
}
|
|
|
|
// Write this workspace using the given writer.
|
|
func (w *cmakeWorkspace) write(writer io.Writer) (int, error) {
|
|
var state writeState
|
|
nb := 0
|
|
for _, r := range w.rules {
|
|
num, err := w.writeRule(writer, r, &state)
|
|
if err != nil {
|
|
return nb, skerr.Wrap(err)
|
|
}
|
|
nb += num
|
|
}
|
|
return nb, nil
|
|
}
|