blob: a207b19cf87a46584388e13c0efd8c5841de5da4 [file] [log] [blame]
// Copyright 2023 The Dawn & Tint Authors.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package build
import (
"sort"
"dawn.googlesource.com/dawn/tools/src/container"
"dawn.googlesource.com/dawn/tools/src/transform"
)
// Target holds information about a build target
type Target struct {
// The target's name
Name TargetName
// The kind of target
Kind TargetKind
// The directory holding the target
Directory *Directory
// All project-relative paths of source files that are part of this target
SourceFileSet container.Set[string]
// All project-relative paths of files generated by this target
GeneratedFileSet container.Set[string]
// Dependencies of this target
Dependencies *Dependencies
// An optional custom output name for the target
OutputName string
// An optional condition for building this target
Condition Condition
}
// AddSourceFile adds the File to the target's source file set
func (t *Target) AddSourceFile(f *File) {
if f.IsGenerated {
panic("attempting to add a generated file to SourceFileSet")
}
t.SourceFileSet.Add(f.Path())
f.Target = t
}
// AddGeneratedFile adds the File to the target's generated file set
func (t *Target) AddGeneratedFile(f *File) {
if !f.IsGenerated {
panic("attempting to add a non-generated file to GeneratedFileSet")
}
t.GeneratedFileSet.Add(f.Path())
f.Target = t
}
// SourceFiles returns the sorted list of the target's source files
func (t *Target) SourceFiles() []*File {
out := make([]*File, len(t.SourceFileSet))
for i, name := range t.SourceFileSet.List() {
out[i] = t.Directory.Project.Files[name]
}
return out
}
// UnconditionalSourceFiles returns the sorted list of the target's source files that have no build condition
func (t *Target) UnconditionalSourceFiles() []*File {
return transform.Filter(t.SourceFiles(), func(t *File) bool { return t.Condition == nil })
}
// TargetConditional is a collection of source files and dependencies sharing the same condition
type TargetConditional struct {
Condition Condition
SourceFiles []*File
InternalDependencies []*Target
ExternalDependencies []ExternalDependency
}
// TargetConditionals is a collection of source files and dependencies sharing the same condition
type TargetConditionals []*TargetConditional
// HasSourceFiles returns true if any of the conditionals in l have source files
func (l TargetConditionals) HasSourceFiles() bool {
for _, c := range l {
if len(c.SourceFiles) > 0 {
return true
}
}
return false
}
// HasDependencies returns true if any of the conditionals in l have internal or external dependencies
func (l TargetConditionals) HasDependencies() bool {
for _, c := range l {
if len(c.InternalDependencies) > 0 || len(c.ExternalDependencies) > 0 {
return true
}
}
return false
}
// Conditionals returns a sorted list of TargetConditional, which are grouped by condition
func (t *Target) Conditionals() TargetConditionals {
m := container.NewMap[string, *TargetConditional]()
for name := range t.SourceFileSet {
file := t.Directory.Project.Files[name]
if file.Condition != nil {
c := m.GetOrCreate(file.Condition.String(), func() *TargetConditional {
return &TargetConditional{Condition: file.Condition}
})
c.SourceFiles = append(c.SourceFiles, file)
}
}
for name := range t.Dependencies.internal {
dep := t.Directory.Project.Targets[name]
if dep.Condition != nil {
c := m.GetOrCreate(dep.Condition.String(), func() *TargetConditional {
return &TargetConditional{Condition: dep.Condition}
})
c.InternalDependencies = append(c.InternalDependencies, dep)
}
}
for name := range t.Dependencies.external {
dep := t.Directory.Project.externals[name]
if dep.Condition != nil {
c := m.GetOrCreate(dep.Condition.String(), func() *TargetConditional {
return &TargetConditional{Condition: dep.Condition}
})
c.ExternalDependencies = append(c.ExternalDependencies, dep)
}
}
for _, c := range m {
sort.Slice(c.SourceFiles, func(a, b int) bool { return c.SourceFiles[a].Name < c.SourceFiles[b].Name })
sort.Slice(c.InternalDependencies, func(a, b int) bool { return c.InternalDependencies[a].Name < c.InternalDependencies[b].Name })
sort.Slice(c.ExternalDependencies, func(a, b int) bool { return c.ExternalDependencies[a].Name < c.ExternalDependencies[b].Name })
}
return TargetConditionals(m.Values())
}