Compare commits
7 Commits
v0.11.6
...
xgopilot/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
940c6f7625 | ||
|
|
3348b645af | ||
|
|
6c85cf7594 | ||
|
|
f3e5ad536d | ||
|
|
c0a3a19294 | ||
|
|
c36ccfd9a1 | ||
|
|
060a2dea06 |
117
.github/workflows/export_test.sh
vendored
Executable file
117
.github/workflows/export_test.sh
vendored
Executable file
@@ -0,0 +1,117 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Test script for //export with different symbol names
|
||||||
|
# This is essential for embedded development where hardware specifications require
|
||||||
|
# specific symbol names (e.g., ARM Cortex-M interrupt handlers).
|
||||||
|
|
||||||
|
set -e # Exit on any error
|
||||||
|
|
||||||
|
# Use current working directory (workflow already cd's to the test directory)
|
||||||
|
WORK_DIR="$(pwd)"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Function to print colored output
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if llgo command is available
|
||||||
|
if ! command -v llgo &> /dev/null; then
|
||||||
|
print_error "llgo command not found, please install llgo first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if LLGO_ROOT is set
|
||||||
|
if [[ -z "$LLGO_ROOT" ]]; then
|
||||||
|
print_error "LLGO_ROOT environment variable is not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Starting export symbol name test..."
|
||||||
|
print_status "Working directory: $WORK_DIR"
|
||||||
|
print_status "LLGO_ROOT: $LLGO_ROOT"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Build the test program
|
||||||
|
print_status "=== Building test program ==="
|
||||||
|
if llgo build -o test_export main.go; then
|
||||||
|
print_status "Build succeeded"
|
||||||
|
else
|
||||||
|
print_error "Build failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for expected symbols using nm
|
||||||
|
print_status "=== Checking exported symbols with nm ==="
|
||||||
|
if ! command -v nm &> /dev/null; then
|
||||||
|
print_error "nm command not found, skipping symbol verification"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
NM_OUTPUT=$(nm test_export)
|
||||||
|
|
||||||
|
# Verify LPSPI2_IRQHandler symbol exists (not interruptLPSPI2)
|
||||||
|
if echo "$NM_OUTPUT" | grep -q "LPSPI2_IRQHandler"; then
|
||||||
|
print_status "✓ Symbol LPSPI2_IRQHandler found"
|
||||||
|
else
|
||||||
|
print_error "✗ Symbol LPSPI2_IRQHandler not found"
|
||||||
|
echo "Available symbols:"
|
||||||
|
echo "$NM_OUTPUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify SysTick_Handler symbol exists (not systemTickHandler)
|
||||||
|
if echo "$NM_OUTPUT" | grep -q "SysTick_Handler"; then
|
||||||
|
print_status "✓ Symbol SysTick_Handler found"
|
||||||
|
else
|
||||||
|
print_error "✗ Symbol SysTick_Handler not found"
|
||||||
|
echo "Available symbols:"
|
||||||
|
echo "$NM_OUTPUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify Add symbol exists (same name)
|
||||||
|
if echo "$NM_OUTPUT" | grep -q "Add"; then
|
||||||
|
print_status "✓ Symbol Add found"
|
||||||
|
else
|
||||||
|
print_error "✗ Symbol Add not found"
|
||||||
|
echo "Available symbols:"
|
||||||
|
echo "$NM_OUTPUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify that the original function names are NOT exported as main symbols
|
||||||
|
# (they should only appear as internal symbols, not as exported text symbols 'T')
|
||||||
|
EXPORTED_SYMBOLS=$(echo "$NM_OUTPUT" | grep " T " || true)
|
||||||
|
|
||||||
|
if echo "$EXPORTED_SYMBOLS" | grep -q "interruptLPSPI2"; then
|
||||||
|
print_error "✗ Unexpected exported symbol: interruptLPSPI2 (should be LPSPI2_IRQHandler)"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
print_status "✓ interruptLPSPI2 not exported as main symbol"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if echo "$EXPORTED_SYMBOLS" | grep -q "systemTickHandler"; then
|
||||||
|
print_error "✗ Unexpected exported symbol: systemTickHandler (should be SysTick_Handler)"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
print_status "✓ systemTickHandler not exported as main symbol"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_status "=== All symbol name tests passed! ==="
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
rm -f test_export
|
||||||
|
|
||||||
|
print_status "Export symbol name test completed successfully!"
|
||||||
101
.github/workflows/export_test_normal.sh
vendored
Normal file
101
.github/workflows/export_test_normal.sh
vendored
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Test script for //export on normal (non-baremetal) targets
|
||||||
|
# This ensures that //export with different symbol names does NOT work on normal targets
|
||||||
|
|
||||||
|
set -e # Exit on any error
|
||||||
|
|
||||||
|
# Use current working directory (workflow already cd's to the test directory)
|
||||||
|
WORK_DIR="$(pwd)"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Function to print colored output
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if llgo command is available
|
||||||
|
if ! command -v llgo &> /dev/null; then
|
||||||
|
print_error "llgo command not found, please install llgo first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if LLGO_ROOT is set
|
||||||
|
if [[ -z "$LLGO_ROOT" ]]; then
|
||||||
|
print_error "LLGO_ROOT environment variable is not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Starting export symbol name test for normal targets..."
|
||||||
|
print_status "Working directory: $WORK_DIR"
|
||||||
|
print_status "LLGO_ROOT: $LLGO_ROOT"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Build the test program
|
||||||
|
print_status "=== Building test program ==="
|
||||||
|
if llgo build -o test_export main.go; then
|
||||||
|
print_status "Build succeeded"
|
||||||
|
else
|
||||||
|
print_error "Build failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for expected symbols using nm
|
||||||
|
print_status "=== Checking exported symbols with nm ==="
|
||||||
|
if ! command -v nm &> /dev/null; then
|
||||||
|
print_error "nm command not found, skipping symbol verification"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
NM_OUTPUT=$(nm test_export)
|
||||||
|
|
||||||
|
# For normal targets, //export SymbolName should export the FUNCTION NAME, not the symbol name
|
||||||
|
# So we expect LPSPI2_IRQHandler, SysTick_Handler, Add (the function names)
|
||||||
|
|
||||||
|
# Verify LPSPI2_IRQHandler symbol exists (function name)
|
||||||
|
if echo "$NM_OUTPUT" | grep -q "LPSPI2_IRQHandler"; then
|
||||||
|
print_status "✓ Symbol LPSPI2_IRQHandler found (function name)"
|
||||||
|
else
|
||||||
|
print_error "✗ Symbol LPSPI2_IRQHandler not found"
|
||||||
|
echo "Available symbols:"
|
||||||
|
echo "$NM_OUTPUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify SysTick_Handler symbol exists (function name)
|
||||||
|
if echo "$NM_OUTPUT" | grep -q "SysTick_Handler"; then
|
||||||
|
print_status "✓ Symbol SysTick_Handler found (function name)"
|
||||||
|
else
|
||||||
|
print_error "✗ Symbol SysTick_Handler not found"
|
||||||
|
echo "Available symbols:"
|
||||||
|
echo "$NM_OUTPUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify Add symbol exists (same name)
|
||||||
|
if echo "$NM_OUTPUT" | grep -q "Add"; then
|
||||||
|
print_status "✓ Symbol Add found"
|
||||||
|
else
|
||||||
|
print_error "✗ Symbol Add not found"
|
||||||
|
echo "Available symbols:"
|
||||||
|
echo "$NM_OUTPUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_status "=== All symbol name tests passed for normal targets! ==="
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
rm -f test_export
|
||||||
|
|
||||||
|
print_status "Export symbol name test for normal targets completed successfully!"
|
||||||
14
.github/workflows/llgo.yml
vendored
14
.github/workflows/llgo.yml
vendored
@@ -133,6 +133,20 @@ jobs:
|
|||||||
chmod +x test.sh
|
chmod +x test.sh
|
||||||
./test.sh
|
./test.sh
|
||||||
|
|
||||||
|
- name: Test export symbol names for embedded targets
|
||||||
|
run: |
|
||||||
|
echo "Testing //export with different symbol names for embedded development..."
|
||||||
|
chmod +x .github/workflows/export_test.sh
|
||||||
|
cd _demo/embed/export
|
||||||
|
bash ../../../.github/workflows/export_test.sh
|
||||||
|
|
||||||
|
- name: Test export symbol names for normal targets
|
||||||
|
run: |
|
||||||
|
echo "Testing //export behavior for normal (non-embedded) targets..."
|
||||||
|
chmod +x .github/workflows/export_test_normal.sh
|
||||||
|
cd _demo/normal/export
|
||||||
|
bash ../../../.github/workflows/export_test_normal.sh
|
||||||
|
|
||||||
- name: _xtool build tests
|
- name: _xtool build tests
|
||||||
run: |
|
run: |
|
||||||
cd _xtool
|
cd _xtool
|
||||||
|
|||||||
22
_demo/embed/export/main.go
Normal file
22
_demo/embed/export/main.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
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))
|
||||||
|
}
|
||||||
22
_demo/normal/export/main.go
Normal file
22
_demo/normal/export/main.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
//export LPSPI2_IRQHandler
|
||||||
|
func LPSPI2_IRQHandler() {
|
||||||
|
println("LPSPI2 interrupt handled")
|
||||||
|
}
|
||||||
|
|
||||||
|
//export SysTick_Handler
|
||||||
|
func SysTick_Handler() {
|
||||||
|
println("System tick")
|
||||||
|
}
|
||||||
|
|
||||||
|
//export Add
|
||||||
|
func Add(a, b int) int {
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
LPSPI2_IRQHandler()
|
||||||
|
SysTick_Handler()
|
||||||
|
println("Add(2, 3) =", Add(2, 3))
|
||||||
|
}
|
||||||
33
cl/import.go
33
cl/import.go
@@ -278,7 +278,8 @@ func (p *context) initLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName s
|
|||||||
for n := len(doc.List) - 1; n >= 0; n-- {
|
for n := len(doc.List) - 1; n >= 0; n-- {
|
||||||
line := doc.List[n].Text
|
line := doc.List[n].Text
|
||||||
ret := p.initLinkname(line, func(name string) (_ string, _, ok bool) {
|
ret := p.initLinkname(line, func(name string) (_ string, _, ok bool) {
|
||||||
return fullName, isVar, name == inPkgName
|
// support empty name for //export directive
|
||||||
|
return fullName, isVar, name == inPkgName || name == ""
|
||||||
})
|
})
|
||||||
if ret != unknownDirective {
|
if ret != unknownDirective {
|
||||||
return ret == hasLinkname
|
return ret == hasLinkname
|
||||||
@@ -312,10 +313,32 @@ func (p *context) initLinkname(line string, f func(inPkgName string) (fullName s
|
|||||||
p.initLink(line, len(llgolink), false, f)
|
p.initLink(line, len(llgolink), false, f)
|
||||||
return hasLinkname
|
return hasLinkname
|
||||||
} else if strings.HasPrefix(line, export) {
|
} else if strings.HasPrefix(line, export) {
|
||||||
// rewrite //export FuncName to //export FuncName FuncName
|
// support //export ExportName
|
||||||
funcName := strings.TrimSpace(line[len(export):])
|
// format: //export ExportName or //export FuncName ExportName
|
||||||
line = line + " " + funcName
|
exportName := strings.TrimSpace(line[len(export):])
|
||||||
p.initLink(line, len(export), true, f)
|
var inPkgName string
|
||||||
|
isBaremetal := os.Getenv("LLGO_TARGET_BAREMETAL") == "1"
|
||||||
|
if idx := strings.IndexByte(exportName, ' '); idx > 0 {
|
||||||
|
// format: //export FuncName ExportName (go-style)
|
||||||
|
inPkgName = exportName[:idx]
|
||||||
|
exportName = strings.TrimLeft(exportName[idx+1:], " ")
|
||||||
|
} else {
|
||||||
|
// format: //export ExportName (tinygo-style, only for baremetal targets)
|
||||||
|
if !isBaremetal {
|
||||||
|
// For non-baremetal targets, treat as function name (standard Go behavior)
|
||||||
|
inPkgName = exportName
|
||||||
|
} else {
|
||||||
|
// For baremetal targets, use empty string to match any function
|
||||||
|
inPkgName = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fullName, _, ok := f(inPkgName); ok {
|
||||||
|
p.prog.SetLinkname(fullName, exportName)
|
||||||
|
p.pkg.SetExport(fullName, exportName)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(os.Stderr, "==>", line)
|
||||||
|
fmt.Fprintf(os.Stderr, "llgo: export %s not found and ignored\n", inPkgName)
|
||||||
|
}
|
||||||
return hasLinkname
|
return hasLinkname
|
||||||
} else if strings.HasPrefix(line, directive) {
|
} else if strings.HasPrefix(line, directive) {
|
||||||
// skip unknown annotation but continue to parse the next annotation
|
// skip unknown annotation but continue to parse the next annotation
|
||||||
|
|||||||
@@ -222,6 +222,13 @@ func Do(args []string, conf *Config) ([]Package, error) {
|
|||||||
}
|
}
|
||||||
if len(export.BuildTags) > 0 {
|
if len(export.BuildTags) > 0 {
|
||||||
tags += "," + strings.Join(export.BuildTags, ",")
|
tags += "," + strings.Join(export.BuildTags, ",")
|
||||||
|
// Set environment variable if building for baremetal target
|
||||||
|
for _, tag := range export.BuildTags {
|
||||||
|
if tag == "baremetal" {
|
||||||
|
os.Setenv("LLGO_TARGET_BAREMETAL", "1")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cfg := &packages.Config{
|
cfg := &packages.Config{
|
||||||
Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile,
|
Mode: loadSyntax | packages.NeedDeps | packages.NeedModule | packages.NeedExportFile,
|
||||||
|
|||||||
Reference in New Issue
Block a user