189 lines
4.3 KiB
Go
189 lines
4.3 KiB
Go
package targets
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// Loader handles loading and parsing target configurations
|
|
type Loader struct {
|
|
targetsDir string
|
|
cache map[string]*RawConfig
|
|
}
|
|
|
|
// NewLoader creates a new target configuration loader
|
|
func NewLoader(targetsDir string) *Loader {
|
|
return &Loader{
|
|
targetsDir: targetsDir,
|
|
cache: make(map[string]*RawConfig),
|
|
}
|
|
}
|
|
|
|
// LoadRaw loads a raw configuration without resolving inheritance
|
|
func (l *Loader) LoadRaw(name string) (*RawConfig, error) {
|
|
// Check cache first
|
|
if config, exists := l.cache[name]; exists {
|
|
return config, nil
|
|
}
|
|
|
|
// Construct file path
|
|
configPath := filepath.Join(l.targetsDir, name+".json")
|
|
|
|
// Read file
|
|
data, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read target config %s: %w", name, err)
|
|
}
|
|
|
|
// Parse JSON
|
|
var config RawConfig
|
|
if err := json.Unmarshal(data, &config); err != nil {
|
|
return nil, fmt.Errorf("failed to parse target config %s: %w", name, err)
|
|
}
|
|
|
|
// Set the name
|
|
config.Name = name
|
|
|
|
// Cache the result
|
|
l.cache[name] = &config
|
|
|
|
return &config, nil
|
|
}
|
|
|
|
// Load loads a target configuration with inheritance resolved
|
|
func (l *Loader) Load(name string) (*Config, error) {
|
|
raw, err := l.LoadRaw(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return l.resolveInheritance(raw)
|
|
}
|
|
|
|
// LoadAll loads all target configurations in the targets directory
|
|
func (l *Loader) LoadAll() (map[string]*Config, error) {
|
|
entries, err := os.ReadDir(l.targetsDir)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read targets directory: %w", err)
|
|
}
|
|
|
|
configs := make(map[string]*Config)
|
|
|
|
for _, entry := range entries {
|
|
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") {
|
|
continue
|
|
}
|
|
|
|
name := strings.TrimSuffix(entry.Name(), ".json")
|
|
config, err := l.Load(name)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load target %s: %w", name, err)
|
|
}
|
|
|
|
configs[name] = config
|
|
}
|
|
|
|
return configs, nil
|
|
}
|
|
|
|
// resolveInheritance resolves inheritance chain for a configuration
|
|
func (l *Loader) resolveInheritance(raw *RawConfig) (*Config, error) {
|
|
if !raw.HasInheritance() {
|
|
// No inheritance, return as-is
|
|
return &raw.Config, nil
|
|
}
|
|
|
|
// Start with base config
|
|
result := &Config{Name: raw.Name}
|
|
|
|
// Apply inheritance in order
|
|
for _, parentName := range raw.GetInherits() {
|
|
parent, err := l.Load(parentName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load parent config %s: %w", parentName, err)
|
|
}
|
|
|
|
// Merge parent into result
|
|
l.mergeConfig(result, parent)
|
|
}
|
|
|
|
// Finally, apply current config on top
|
|
l.mergeConfig(result, &raw.Config)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// mergeConfig merges source config into destination config
|
|
// Non-empty values in source override those in destination
|
|
func (l *Loader) mergeConfig(dst, src *Config) {
|
|
if src.LLVMTarget != "" {
|
|
dst.LLVMTarget = src.LLVMTarget
|
|
}
|
|
if src.CPU != "" {
|
|
dst.CPU = src.CPU
|
|
}
|
|
if src.Features != "" {
|
|
dst.Features = src.Features
|
|
}
|
|
if src.GOOS != "" {
|
|
dst.GOOS = src.GOOS
|
|
}
|
|
if src.GOARCH != "" {
|
|
dst.GOARCH = src.GOARCH
|
|
}
|
|
if src.Linker != "" {
|
|
dst.Linker = src.Linker
|
|
}
|
|
if src.LinkerScript != "" {
|
|
dst.LinkerScript = src.LinkerScript
|
|
}
|
|
if src.CodeModel != "" {
|
|
dst.CodeModel = src.CodeModel
|
|
}
|
|
if src.TargetABI != "" {
|
|
dst.TargetABI = src.TargetABI
|
|
}
|
|
if src.RelocationModel != "" {
|
|
dst.RelocationModel = src.RelocationModel
|
|
}
|
|
|
|
// Merge slices (append, don't replace)
|
|
if len(src.BuildTags) > 0 {
|
|
dst.BuildTags = append(dst.BuildTags, src.BuildTags...)
|
|
}
|
|
if len(src.CFlags) > 0 {
|
|
dst.CFlags = append(dst.CFlags, src.CFlags...)
|
|
}
|
|
if len(src.LDFlags) > 0 {
|
|
dst.LDFlags = append(dst.LDFlags, src.LDFlags...)
|
|
}
|
|
}
|
|
|
|
// GetTargetsDir returns the targets directory path
|
|
func (l *Loader) GetTargetsDir() string {
|
|
return l.targetsDir
|
|
}
|
|
|
|
// ListTargets returns a list of all available target names
|
|
func (l *Loader) ListTargets() ([]string, error) {
|
|
entries, err := os.ReadDir(l.targetsDir)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read targets directory: %w", err)
|
|
}
|
|
|
|
var targets []string
|
|
for _, entry := range entries {
|
|
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".json") {
|
|
continue
|
|
}
|
|
|
|
name := strings.TrimSuffix(entry.Name(), ".json")
|
|
targets = append(targets, name)
|
|
}
|
|
|
|
return targets, nil
|
|
}
|