diff --git a/_demo/embedded/export_test/main.go b/_demo/embedded/export_test/main.go deleted file mode 100644 index ec29c390..00000000 --- a/_demo/embedded/export_test/main.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -//export LPSPI2_IRQHandler -func interruptLPSPI2() { - println("LPSPI2 interrupt handled") -} - -//export SysTick_Handler -func systemTickHandler() { - println("System tick") -} - -//export Add -func Add(a, b int) int { - return a + b -} - -func main() { - interruptLPSPI2() - systemTickHandler() - println("Add(2, 3) =", Add(2, 3)) -} diff --git a/_demo/embedded/export_test/test.sh b/_demo/embedded/export_test/test.sh deleted file mode 100755 index 402850bb..00000000 --- a/_demo/embedded/export_test/test.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -set -e - -echo "Testing //export with different symbol names..." - -# Set LLGO_ROOT to repository root -export LLGO_ROOT=/workspace - -# Build the test program -echo "Building test program..." -/workspace/llgo build -o test_export main.go || exit 1 - -# Check for expected symbols using nm -echo "Verifying symbols with nm..." - -# Should find LPSPI2_IRQHandler (not interruptLPSPI2) -if nm test_export | grep -q "T LPSPI2_IRQHandler"; then - echo "✓ Symbol LPSPI2_IRQHandler found" -else - echo "✗ Symbol LPSPI2_IRQHandler not found" - echo "Available symbols:" - nm test_export | grep " T " - exit 1 -fi - -# Should find SysTick_Handler (not systemTickHandler) -if nm test_export | grep -q "T SysTick_Handler"; then - echo "✓ Symbol SysTick_Handler found" -else - echo "✗ Symbol SysTick_Handler not found" - exit 1 -fi - -# Should find Add (same name) -if nm test_export | grep -q "T Add"; then - echo "✓ Symbol Add found" -else - echo "✗ Symbol Add not found" - exit 1 -fi - -echo "" -echo "All symbol checks passed! ✓" diff --git a/test/export_test.go b/test/export_test.go new file mode 100644 index 00000000..88b273dc --- /dev/null +++ b/test/export_test.go @@ -0,0 +1,160 @@ +//go:build !llgo +// +build !llgo + +package test + +import ( + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +// TestExportSymbolNames tests that //export directive supports different symbol names +// This is essential for embedded development where hardware specifications require +// specific symbol names (e.g., ARM Cortex-M interrupt handlers). +func TestExportSymbolNames(t *testing.T) { + // Create temporary directory for test + tmpDir, err := os.MkdirTemp("", "llgo-export-test-*") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + // Write test program + testCode := `package main + +//export LPSPI2_IRQHandler +func interruptLPSPI2() { + println("LPSPI2 interrupt handled") +} + +//export SysTick_Handler +func systemTickHandler() { + println("System tick") +} + +//export Add +func Add(a, b int) int { + return a + b +} + +func main() { + interruptLPSPI2() + systemTickHandler() + println("Add(2, 3) =", Add(2, 3)) +} +` + mainGo := filepath.Join(tmpDir, "main.go") + if err := os.WriteFile(mainGo, []byte(testCode), 0644); err != nil { + t.Fatal(err) + } + + // Get llgo binary path + llgoPath := findLLGo(t) + + // Build the test program + testBinary := filepath.Join(tmpDir, "test_export") + cmd := exec.Command(llgoPath, "build", "-o", testBinary, mainGo) + cmd.Env = append(os.Environ(), "LLGO_ROOT="+findLLGORoot(t)) + if output, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("Build failed: %v\nOutput: %s", err, output) + } + + // Check for expected symbols using nm + nmCmd := exec.Command("nm", testBinary) + nmOutput, err := nmCmd.CombinedOutput() + if err != nil { + t.Fatalf("nm command failed: %v\nOutput: %s", err, nmOutput) + } + + nmStr := string(nmOutput) + + // Verify LPSPI2_IRQHandler symbol exists (not interruptLPSPI2) + if !strings.Contains(nmStr, "LPSPI2_IRQHandler") { + t.Errorf("Symbol LPSPI2_IRQHandler not found in binary") + t.Logf("Available symbols:\n%s", nmStr) + } + + // Verify SysTick_Handler symbol exists (not systemTickHandler) + if !strings.Contains(nmStr, "SysTick_Handler") { + t.Errorf("Symbol SysTick_Handler not found in binary") + t.Logf("Available symbols:\n%s", nmStr) + } + + // Verify Add symbol exists (same name) + if !strings.Contains(nmStr, "Add") { + t.Errorf("Symbol Add not found in binary") + t.Logf("Available symbols:\n%s", nmStr) + } + + // Verify that the original function names are NOT exported + // (they should only appear as internal symbols, not exported with 'T') + lines := strings.Split(nmStr, "\n") + for _, line := range lines { + if strings.Contains(line, " T ") || strings.Contains(line, " t ") { + if strings.Contains(line, "interruptLPSPI2") { + t.Errorf("Unexpected exported symbol: interruptLPSPI2 (should be LPSPI2_IRQHandler)") + } + if strings.Contains(line, "systemTickHandler") { + t.Errorf("Unexpected exported symbol: systemTickHandler (should be SysTick_Handler)") + } + } + } +} + +// findLLGo finds the llgo binary +func findLLGo(t *testing.T) string { + t.Helper() + + // Always use the repository version for testing to ensure we test the latest code + root := findLLGORoot(t) + llgoPath := filepath.Join(root, "llgo") + + // Check if it exists + if _, err := os.Stat(llgoPath); err == nil { + return llgoPath + } + + // Try to build it + cmd := exec.Command("go", "build", "-o", llgoPath, "./cmd/llgo") + cmd.Dir = root + if err := cmd.Run(); err != nil { + t.Skipf("llgo cannot be built: %v", err) + } + + return llgoPath +} + +// findLLGORoot finds the LLGO repository root +func findLLGORoot(t *testing.T) string { + t.Helper() + + // Check LLGO_ROOT environment variable + if root := os.Getenv("LLGO_ROOT"); root != "" { + return root + } + + // Try to find it relative to this test file + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + + // Walk up to find go.mod + dir := wd + for { + if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil { + return dir + } + parent := filepath.Dir(dir) + if parent == dir { + break + } + dir = parent + } + + t.Fatal("Cannot find LLGO_ROOT") + return "" +}