expand template vars in targets config
This commit is contained in:
@@ -44,6 +44,83 @@ func cacheDir() string {
|
|||||||
return filepath.Join(env.LLGoCacheDir(), "crosscompile")
|
return filepath.Join(env.LLGoCacheDir(), "crosscompile")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// expandEnv expands template variables in a string
|
||||||
|
// Supports variables like {port}, {hex}, {bin}, {root}, {tmpDir}, etc.
|
||||||
|
// Special case: {} expands to the first available file variable (hex, bin, img, zip)
|
||||||
|
func expandEnv(template string, envs map[string]string) string {
|
||||||
|
return expandEnvWithDefault(template, envs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expandEnvWithDefault expands template variables with optional default for {}
|
||||||
|
func expandEnvWithDefault(template string, envs map[string]string, defaultValue ...string) string {
|
||||||
|
if template == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
result := template
|
||||||
|
|
||||||
|
// Handle special case of {} - use provided default or first available file variable
|
||||||
|
if strings.Contains(result, "{}") {
|
||||||
|
defaultVal := ""
|
||||||
|
if len(defaultValue) > 0 && defaultValue[0] != "" {
|
||||||
|
defaultVal = defaultValue[0]
|
||||||
|
} else {
|
||||||
|
// Priority order: hex, bin, img, zip
|
||||||
|
for _, key := range []string{"hex", "bin", "img", "zip"} {
|
||||||
|
if value, exists := envs[key]; exists && value != "" {
|
||||||
|
defaultVal = value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = strings.ReplaceAll(result, "{}", defaultVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace named variables
|
||||||
|
for key, value := range envs {
|
||||||
|
if key != "" { // Skip empty key used for {} default
|
||||||
|
result = strings.ReplaceAll(result, "{"+key+"}", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// expandEnvSlice expands template variables in a slice of strings
|
||||||
|
func expandEnvSlice(templates []string, envs map[string]string) []string {
|
||||||
|
return expandEnvSliceWithDefault(templates, envs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expandEnvSliceWithDefault expands template variables in a slice with optional default for {}
|
||||||
|
func expandEnvSliceWithDefault(templates []string, envs map[string]string, defaultValue ...string) []string {
|
||||||
|
if len(templates) == 0 {
|
||||||
|
return templates
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]string, len(templates))
|
||||||
|
for i, template := range templates {
|
||||||
|
result[i] = expandEnvWithDefault(template, envs, defaultValue...)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildEnvMap creates a map of template variables for the current context
|
||||||
|
func buildEnvMap(llgoRoot string) map[string]string {
|
||||||
|
envs := make(map[string]string)
|
||||||
|
|
||||||
|
// Basic paths
|
||||||
|
envs["root"] = llgoRoot
|
||||||
|
envs["tmpDir"] = os.TempDir()
|
||||||
|
|
||||||
|
// These will typically be set by calling code when actual values are known
|
||||||
|
// envs["port"] = "" // Serial port (e.g., "/dev/ttyUSB0", "COM3")
|
||||||
|
// envs["hex"] = "" // Path to hex file
|
||||||
|
// envs["bin"] = "" // Path to binary file
|
||||||
|
// envs["img"] = "" // Path to image file
|
||||||
|
// envs["zip"] = "" // Path to zip file
|
||||||
|
|
||||||
|
return envs
|
||||||
|
}
|
||||||
|
|
||||||
// getMacOSSysroot returns the macOS SDK path using xcrun
|
// getMacOSSysroot returns the macOS SDK path using xcrun
|
||||||
func getMacOSSysroot() (string, error) {
|
func getMacOSSysroot() (string, error) {
|
||||||
cmd := exec.Command("xcrun", "--sdk", "macosx", "--show-sdk-path")
|
cmd := exec.Command("xcrun", "--sdk", "macosx", "--show-sdk-path")
|
||||||
@@ -347,6 +424,9 @@ func useTarget(targetName string) (export Export, err error) {
|
|||||||
export.GOOS = config.GOOS
|
export.GOOS = config.GOOS
|
||||||
export.GOARCH = config.GOARCH
|
export.GOARCH = config.GOARCH
|
||||||
|
|
||||||
|
// Build environment map for template variable expansion
|
||||||
|
envs := buildEnvMap(env.LLGoROOT())
|
||||||
|
|
||||||
// Convert LLVMTarget, CPU, Features to CCFLAGS/LDFLAGS
|
// Convert LLVMTarget, CPU, Features to CCFLAGS/LDFLAGS
|
||||||
var ccflags []string
|
var ccflags []string
|
||||||
var ldflags []string
|
var ldflags []string
|
||||||
@@ -361,7 +441,9 @@ func useTarget(targetName string) (export Export, err error) {
|
|||||||
cflags = append(cflags, "--target="+config.LLVMTarget)
|
cflags = append(cflags, "--target="+config.LLVMTarget)
|
||||||
ccflags = append(ccflags, "--target="+config.LLVMTarget)
|
ccflags = append(ccflags, "--target="+config.LLVMTarget)
|
||||||
}
|
}
|
||||||
cflags = append(cflags, config.CFlags...)
|
// Expand template variables in cflags
|
||||||
|
expandedCFlags := expandEnvSlice(config.CFlags, envs)
|
||||||
|
cflags = append(cflags, expandedCFlags...)
|
||||||
|
|
||||||
// Inspired by tinygo
|
// Inspired by tinygo
|
||||||
cpu := config.CPU
|
cpu := config.CPU
|
||||||
@@ -394,10 +476,11 @@ func useTarget(targetName string) (export Export, err error) {
|
|||||||
}
|
}
|
||||||
ldflags = append(ldflags, "-L", env.LLGoROOT()) // search targets/*.ld
|
ldflags = append(ldflags, "-L", env.LLGoROOT()) // search targets/*.ld
|
||||||
|
|
||||||
// Combine with config flags
|
// Combine with config flags and expand template variables
|
||||||
export.CFLAGS = cflags
|
export.CFLAGS = cflags
|
||||||
export.CCFLAGS = ccflags
|
export.CCFLAGS = ccflags
|
||||||
export.LDFLAGS = append(ldflags, config.LDFlags...)
|
expandedLDFlags := expandEnvSlice(config.LDFlags, envs)
|
||||||
|
export.LDFLAGS = append(ldflags, expandedLDFlags...)
|
||||||
|
|
||||||
return export, nil
|
return export, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,3 +301,126 @@ func TestUseWithTarget(t *testing.T) {
|
|||||||
t.Error("Expected LDFLAGS to be set for native build")
|
t.Error("Expected LDFLAGS to be set for native build")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExpandEnv(t *testing.T) {
|
||||||
|
envs := map[string]string{
|
||||||
|
"port": "/dev/ttyUSB0",
|
||||||
|
"hex": "firmware.hex",
|
||||||
|
"bin": "firmware.bin",
|
||||||
|
"root": "/usr/local/llgo",
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
template string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"avrdude -c arduino -p atmega328p -P {port} -U flash:w:{hex}:i",
|
||||||
|
"avrdude -c arduino -p atmega328p -P /dev/ttyUSB0 -U flash:w:firmware.hex:i",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"simavr -m atmega328p -f 16000000 {}",
|
||||||
|
"simavr -m atmega328p -f 16000000 firmware.hex", // {} expands to hex (first priority)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"-I{root}/lib/CMSIS/CMSIS/Include",
|
||||||
|
"-I/usr/local/llgo/lib/CMSIS/CMSIS/Include",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"no variables here",
|
||||||
|
"no variables here",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
result := expandEnv(test.template, envs)
|
||||||
|
if result != test.expected {
|
||||||
|
t.Errorf("expandEnv(%q) = %q, want %q", test.template, result, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpandEnvSlice(t *testing.T) {
|
||||||
|
envs := map[string]string{
|
||||||
|
"root": "/usr/local/llgo",
|
||||||
|
"port": "/dev/ttyUSB0",
|
||||||
|
}
|
||||||
|
|
||||||
|
input := []string{
|
||||||
|
"-I{root}/include",
|
||||||
|
"-DPORT={port}",
|
||||||
|
"static-flag",
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []string{
|
||||||
|
"-I/usr/local/llgo/include",
|
||||||
|
"-DPORT=/dev/ttyUSB0",
|
||||||
|
"static-flag",
|
||||||
|
}
|
||||||
|
|
||||||
|
result := expandEnvSlice(input, envs)
|
||||||
|
|
||||||
|
if len(result) != len(expected) {
|
||||||
|
t.Fatalf("expandEnvSlice length mismatch: got %d, want %d", len(result), len(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, exp := range expected {
|
||||||
|
if result[i] != exp {
|
||||||
|
t.Errorf("expandEnvSlice[%d] = %q, want %q", i, result[i], exp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpandEnvWithDefault(t *testing.T) {
|
||||||
|
envs := map[string]string{
|
||||||
|
"port": "/dev/ttyUSB0",
|
||||||
|
"hex": "firmware.hex",
|
||||||
|
"bin": "firmware.bin",
|
||||||
|
"img": "image.img",
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
template string
|
||||||
|
defaultValue string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"simavr {}",
|
||||||
|
"", // No default - should use hex (priority)
|
||||||
|
"simavr firmware.hex",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"simavr {}",
|
||||||
|
"custom.elf", // Explicit default
|
||||||
|
"simavr custom.elf",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"qemu -kernel {}",
|
||||||
|
"vmlinux", // Custom kernel
|
||||||
|
"qemu -kernel vmlinux",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"no braces here",
|
||||||
|
"ignored",
|
||||||
|
"no braces here",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
var result string
|
||||||
|
if test.defaultValue == "" {
|
||||||
|
result = expandEnvWithDefault(test.template, envs)
|
||||||
|
} else {
|
||||||
|
result = expandEnvWithDefault(test.template, envs, test.defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != test.expected {
|
||||||
|
t.Errorf("Test %d: expandEnvWithDefault(%q, envs, %q) = %q, want %q",
|
||||||
|
i, test.template, test.defaultValue, result, test.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user