Files
llgo/internal/crosscompile/libc_test.go
2025-09-09 18:23:31 +08:00

410 lines
12 KiB
Go

//go:build !llgo
package crosscompile
import (
"fmt"
"path/filepath"
"slices"
"strings"
"testing"
"github.com/goplus/llgo/internal/crosscompile/compile/libc"
"github.com/goplus/llgo/internal/crosscompile/compile/rtlib"
)
func TestGetLibcCompileConfigByName(t *testing.T) {
baseDir := "/test/base"
target := "armv7"
mcpu := "cortex-m4"
needSkipDownload = true
t.Run("EmptyName", func(t *testing.T) {
_, _, err := getLibcCompileConfigByName(baseDir, "", target, mcpu)
if err == nil || err.Error() != "libc name cannot be empty" {
t.Errorf("Expected empty name error, got: %v", err)
}
})
t.Run("UnsupportedLibc", func(t *testing.T) {
_, _, err := getLibcCompileConfigByName(baseDir, "invalid", target, mcpu)
if err == nil || err.Error() != "unsupported libc: invalid" {
t.Errorf("Expected unsupported libc error, got: %v", err)
}
})
t.Run("Picolibc", func(t *testing.T) {
_, cfg, err := getLibcCompileConfigByName(baseDir, "picolibc", target, mcpu)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if len(cfg.Groups) != 1 {
t.Fatalf("Expected 1 group, got %d", len(cfg.Groups))
}
group := cfg.Groups[0]
expectedFile := filepath.Join(baseDir, libc.GetPicolibcConfig().String(), "newlib", "libc", "string", "memmem.c")
if !slices.Contains(group.Files, expectedFile) {
t.Errorf("Expected files [%s], got: %v", expectedFile, group.Files)
}
expectedFlag := "-I" + filepath.Join("/test", "base", libc.GetPicolibcConfig().String())
if !slices.Contains(group.CFlags, expectedFlag) {
t.Errorf("Expected flags [%s], got: %v", expectedFlag, group.CFlags)
}
})
t.Run("NewlibESP32", func(t *testing.T) {
_, cfg, err := getLibcCompileConfigByName(baseDir, "newlib-esp32", target, mcpu)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if len(cfg.Groups) != 3 {
t.Fatalf("Expected 3 group, got %d", len(cfg.Groups))
}
group := cfg.Groups[0]
expectedFile := filepath.Join(baseDir, libc.GetNewlibESP32Config().String(), "libgloss", "xtensa", "crt1-boards.S")
if !slices.Contains(group.Files, expectedFile) {
t.Errorf("Expected files [%s], got: %v", expectedFile, group.Files)
}
expectedFlags := "-I" + filepath.Join(baseDir, libc.GetNewlibESP32Config().String(), "libgloss")
if !slices.Contains(group.CFlags, expectedFlags) {
t.Errorf("Expected flags %v, got: %v", expectedFlags, group.CFlags)
}
})
}
func TestGetRTCompileConfigByName(t *testing.T) {
baseDir := "/test/base"
target := "wasm32"
needSkipDownload = true
t.Run("EmptyName", func(t *testing.T) {
_, _, err := getRTCompileConfigByName(baseDir, "", target)
if err == nil || err.Error() != "rt name cannot be empty" {
t.Errorf("Expected empty name error, got: %v", err)
}
})
t.Run("UnsupportedRT", func(t *testing.T) {
_, _, err := getRTCompileConfigByName(baseDir, "invalid", target)
if err == nil || err.Error() != "unsupported rt: invalid" {
t.Errorf("Expected unsupported rt error, got: %v", err)
}
})
t.Run("CompilerRT", func(t *testing.T) {
_, cfg, err := getRTCompileConfigByName(baseDir, "compiler-rt", target)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if len(cfg.Groups) != 1 {
t.Fatalf("Expected 1 group, got %d", len(cfg.Groups))
}
group := cfg.Groups[0]
expectedFile := filepath.Join(baseDir, rtlib.GetCompilerRTConfig().String(), "lib", "builtins", "absvdi2.c")
if !slices.Contains(group.Files, expectedFile) {
t.Errorf("Expected files [%s], got: %v", expectedFile, group.Files)
}
})
}
// TestCompilerRTCompileConfigPaths tests that file paths in the CompileConfig
// are correctly based on the provided baseDir for various target platforms.
func TestCompilerRTCompileConfigPaths(t *testing.T) {
// Define test cases for different target platforms
tests := []struct {
name string // Test case name
baseDir string // Input base directory
target string // Target platform
expected string // Expected platform-specific file
}{
{
name: "RISC-V 32",
baseDir: "/test/base/dir",
target: "riscv32-unknown-elf",
expected: "riscv/mulsi3.S", // Expected platform file for RISC-V 32
},
{
name: "RISC-V 64",
baseDir: "/another/dir",
target: "riscv64-unknown-elf",
expected: "addtf3.c", // Expected platform file for RISC-V 64
},
{
name: "ARM",
baseDir: "/arm/dir",
target: "armv7-unknown-linux-gnueabihf",
expected: "arm/aeabi_cdcmp.S", // Expected platform file for ARM
},
{
name: "AVR",
baseDir: "/avr/dir",
target: "avr",
expected: "avr/divmodhi4.S", // Expected platform file for AVR
},
{
name: "XTENSA",
baseDir: "/xtensa/dir",
target: "xtensa",
expected: "xtensa/ieee754_sqrtf.S", // Expected platform file for XTENSA
},
}
needSkipDownload = true
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Get the compile configuration for this target
cfg := rtlib.GetCompilerRTCompileConfig(tt.baseDir, tt.target)
// Verify there is at least one compile group
if len(cfg.Groups) == 0 {
t.Fatal("CompileConfig has no groups")
}
group := cfg.Groups[0]
found := false
// Check all files in the group
for _, file := range group.Files {
// Verify file path starts with baseDir
if !strings.HasPrefix(file, tt.baseDir) {
t.Errorf("File path %q should start with baseDir %q", file, tt.baseDir)
}
// Verify file path contains the expected platform-specific file
if strings.Contains(file, tt.expected) {
found = true
// Construct the expected full path
expectedPath := filepath.Join(tt.baseDir, "lib", "builtins", tt.expected)
// Verify the actual path matches the expected path
if file != expectedPath {
t.Errorf("Expected file path %q, got %q", expectedPath, file)
}
}
}
// Verify the platform-specific file was found
if !found {
t.Errorf("Expected platform-specific file %q not found in file list", tt.expected)
}
// Verify the output file name format
expectedOutput := fmt.Sprintf("libclang_builtins-%s.a", tt.target)
if !strings.HasSuffix(group.OutputFileName, expectedOutput) {
t.Errorf("OutputFileName should end with %q, got %q", expectedOutput, group.OutputFileName)
}
})
}
}
// TestCompilerRTCompileConfigPathRelations tests the general path relationships
// in the CompileConfig for a specific target.
func TestCompilerRTCompileConfigPathRelations(t *testing.T) {
baseDir := "/test/base/dir"
target := "riscv64-unknown-elf"
// Get the compile configuration
cfg := rtlib.GetCompilerRTCompileConfig(baseDir, target)
// Verify there is at least one compile group
if len(cfg.Groups) == 0 {
t.Fatal("CompileConfig has no groups")
}
needSkipDownload = true
group := cfg.Groups[0]
// Check all files in the group
for _, file := range group.Files {
// Verify file path starts with baseDir
if !strings.HasPrefix(file, baseDir) {
t.Errorf("File path %q should start with baseDir %q", file, baseDir)
}
// Verify file path contains the expected subdirectory structure
expectedSubdir := filepath.Join(baseDir, "lib", "builtins")
if !strings.Contains(file, expectedSubdir) {
t.Errorf("File path %q should contain %q", file, expectedSubdir)
}
}
// Verify the output file name format
expectedOutput := fmt.Sprintf("libclang_builtins-%s.a", target)
if !strings.HasSuffix(group.OutputFileName, expectedOutput) {
t.Errorf("OutputFileName should end with %q, got %q", expectedOutput, group.OutputFileName)
}
}
// TestGetPicolibcCompileConfigPaths tests that all paths in the CompileConfig
// are correctly based on the provided baseDir.
func TestGetPicolibcCompileConfigPaths(t *testing.T) {
// Define test cases with different base directories
tests := []struct {
name string
baseDir string
target string
}{
{
name: "Unix-like path",
baseDir: "/test/base/dir",
target: "riscv64-unknown-elf",
},
{
name: "Windows-like path",
baseDir: "C:\\test\\base\\dir",
target: "x86_64-pc-windows-msvc",
},
{
name: "Relative path",
baseDir: "test/base/dir",
target: "armv7-unknown-linux-gnueabihf",
},
}
needSkipDownload = true
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Get the compile configuration
cfg := libc.GetPicolibcCompileConfig(tt.baseDir, tt.target)
// Verify ExportCFlags paths
for _, flag := range cfg.ExportCFlags {
if strings.HasPrefix(flag, "-I") || strings.HasPrefix(flag, "-isystem") {
path := strings.TrimPrefix(flag, "-I")
path = strings.TrimPrefix(path, "-isystem")
path = strings.TrimSpace(path)
if !strings.HasPrefix(path, tt.baseDir) {
t.Errorf("ExportCFlags path %q should start with baseDir %q", path, tt.baseDir)
}
}
}
// Verify there is at least one compile group
if len(cfg.Groups) == 0 {
t.Fatal("CompileConfig has no groups")
}
group := cfg.Groups[0]
// Verify output file name format
expectedOutput := fmt.Sprintf("libc-%s.a", tt.target)
if group.OutputFileName != expectedOutput {
t.Errorf("Expected OutputFileName %q, got %q", expectedOutput, group.OutputFileName)
}
// Verify all file paths start with baseDir
for _, file := range group.Files {
if !strings.HasPrefix(file, tt.baseDir) {
t.Errorf("File path %q should start with baseDir %q", file, tt.baseDir)
}
// Verify file path contains expected subdirectories
if !strings.Contains(file, filepath.Join(tt.baseDir, "newlib")) {
t.Errorf("File path %q should contain 'newlib' subdirectory", file)
}
}
// Verify CFlags paths
for _, flag := range group.CFlags {
if strings.HasPrefix(flag, "-I") {
path := strings.TrimPrefix(flag, "-I")
path = strings.TrimSpace(path)
if !strings.HasPrefix(path, tt.baseDir) {
t.Errorf("CFlags path %q should start with baseDir %q", path, tt.baseDir)
}
}
}
})
}
}
// TestGetPicolibcCompileConfigSpecificPaths tests specific path constructions
// in the CompileConfig for a given baseDir and target.
func TestGetPicolibcCompileConfigSpecificPaths(t *testing.T) {
baseDir := "/test/base/dir"
target := "riscv64-unknown-elf"
needSkipDownload = true
// Get the compile configuration
cfg := libc.GetPicolibcCompileConfig(baseDir, target)
// Verify ExportCFlags
expectedInclude := filepath.Join(baseDir, "newlib", "libc", "include")
foundInclude := false
for _, flag := range cfg.ExportCFlags {
if flag == "-I"+baseDir || flag == "-isystem"+expectedInclude {
foundInclude = true
}
}
if !foundInclude {
t.Errorf("Expected ExportCFlags to contain -I%s and -isystem%s", baseDir, expectedInclude)
}
// Verify there is at least one compile group
if len(cfg.Groups) == 0 {
t.Fatal("CompileConfig has no groups")
}
group := cfg.Groups[0]
// Verify output file name
expectedOutput := fmt.Sprintf("libc-%s.a", target)
if group.OutputFileName != expectedOutput {
t.Errorf("Expected OutputFileName %q, got %q", expectedOutput, group.OutputFileName)
}
// Verify specific file paths
expectedFiles := []string{
filepath.Join(baseDir, "newlib", "libc", "string", "memcpy.c"),
filepath.Join(baseDir, "newlib", "libc", "string", "strlen.c"),
filepath.Join(baseDir, "newlib", "libc", "stdlib", "nano-malloc.c"),
filepath.Join(baseDir, "newlib", "libc", "tinystdio", "printf.c"),
}
for _, expected := range expectedFiles {
found := false
for _, file := range group.Files {
if file == expected {
found = true
break
}
}
if !found {
t.Errorf("Expected file %q not found in file list", expected)
}
}
// Verify CFlags paths
expectedCFlags := []string{
"-I" + baseDir,
"-isystem" + filepath.Join(baseDir, "newlib", "libc", "include"),
"-I" + filepath.Join(baseDir, "newlib", "libm", "common"),
"-I" + filepath.Join(baseDir, "newlib", "libc", "locale"),
"-I" + filepath.Join(baseDir, "newlib", "libc", "tinystdio"),
}
for _, expected := range expectedCFlags {
found := false
for _, flag := range group.CFlags {
if flag == expected {
found = true
break
}
}
if !found {
t.Errorf("Expected CFlag %q not found", expected)
}
}
}