From dac3365c7371a1060a96a7089a5ac5c5dd79fcf1 Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Mon, 10 Nov 2025 18:52:36 +0800 Subject: [PATCH] cl,build: support //export with different names on embedded targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for using different C symbol names in //export directives when compiling for embedded targets (enabled via -target flag). This is for TinyGo compatibility on embedded platforms where hardware interrupt handlers often require specific naming conventions. Implementation: - Add EnableExportRename() to control export rename behavior - Add isExport parameter to initLink callback for context awareness - Update initLinknameByDoc() to handle export rename logic: * When isExport && enableExportRename: allow different names * Otherwise: require name match - Clean error handling in initLink(): * export + enableExportRename: silent return (already processed) * export + !enableExportRename: panic with clear error message * other cases: warning for missing linkname Example: //export LPSPI2_IRQHandler func interruptLPSPI2() { ... } The Go function is named interruptLPSPI2 but exported as LPSPI2_IRQHandler for the hardware vector table. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- cl/compile.go | 11 +++++++++++ cl/import.go | 19 +++++++++++++------ internal/build/build.go | 5 +++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/cl/compile.go b/cl/compile.go index 9521ff14..433d2efa 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -53,6 +53,11 @@ var ( enableDbg bool enableDbgSyms bool disableInline bool + + // enableExportRename enables //export to use different C symbol names than Go function names. + // This is for TinyGo compatibility when using -target flag for embedded targets. + // Currently, using -target implies TinyGo embedded target mode. + enableExportRename bool ) // SetDebug sets debug flags. @@ -73,6 +78,12 @@ func EnableTrace(b bool) { enableCallTracing = b } +// EnableExportRename enables or disables //export with different C symbol names. +// This is enabled when using -target flag for TinyGo compatibility. +func EnableExportRename(b bool) { + enableExportRename = b +} + // ----------------------------------------------------------------------------- type instrOrValue interface { diff --git a/cl/import.go b/cl/import.go index ea472819..cb309c5a 100644 --- a/cl/import.go +++ b/cl/import.go @@ -73,7 +73,7 @@ func (p *pkgSymInfo) initLinknames(ctx *context) { lines := bytes.Split(b, sep) for _, line := range lines { if bytes.HasPrefix(line, commentPrefix) { - ctx.initLinkname(string(line), func(inPkgName string) (fullName string, isVar, ok bool) { + ctx.initLinkname(string(line), func(inPkgName string, isExport bool) (fullName string, isVar, ok bool) { if sym, ok := p.syms[inPkgName]; ok && file == sym.file { return sym.fullName, sym.isVar, true } @@ -277,8 +277,8 @@ func (p *context) initLinknameByDoc(doc *ast.CommentGroup, fullName, inPkgName s if doc != nil { for n := len(doc.List) - 1; n >= 0; n-- { line := doc.List[n].Text - ret := p.initLinkname(line, func(name string) (_ string, _, ok bool) { - return fullName, isVar, name == inPkgName + ret := p.initLinkname(line, func(name string, isExport bool) (_ string, _, ok bool) { + return fullName, isVar, name == inPkgName || (isExport && enableExportRename) }) if ret != unknownDirective { return ret == hasLinkname @@ -294,7 +294,7 @@ const ( unknownDirective = -1 ) -func (p *context) initLinkname(line string, f func(inPkgName string) (fullName string, isVar, ok bool)) int { +func (p *context) initLinkname(line string, f func(inPkgName string, isExport bool) (fullName string, isVar, ok bool)) int { const ( linkname = "//go:linkname " llgolink = "//llgo:link " @@ -324,17 +324,24 @@ func (p *context) initLinkname(line string, f func(inPkgName string) (fullName s return noDirective } -func (p *context) initLink(line string, prefix int, export bool, f func(inPkgName string) (fullName string, isVar, ok bool)) { +func (p *context) initLink(line string, prefix int, export bool, f func(inPkgName string, isExport bool) (fullName string, isVar, ok bool)) { text := strings.TrimSpace(line[prefix:]) if idx := strings.IndexByte(text, ' '); idx > 0 { inPkgName := text[:idx] - if fullName, _, ok := f(inPkgName); ok { + if fullName, _, ok := f(inPkgName, export); ok { link := strings.TrimLeft(text[idx+1:], " ") p.prog.SetLinkname(fullName, link) if export { p.pkg.SetExport(fullName, link) } } else { + // Export with different names already processed by initLinknameByDoc + if export && enableExportRename { + return + } + if export { + panic(fmt.Sprintf("export comment has wrong name %q", inPkgName)) + } fmt.Fprintln(os.Stderr, "==>", line) fmt.Fprintf(os.Stderr, "llgo: linkname %s not found and ignored\n", inPkgName) } diff --git a/internal/build/build.go b/internal/build/build.go index 1147d495..13df5247 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -214,6 +214,11 @@ func Do(args []string, conf *Config) ([]Package, error) { conf.Goarch = export.GOARCH } + // Enable different export names for TinyGo compatibility when using -target + if conf.Target != "" { + cl.EnableExportRename(true) + } + verbose := conf.Verbose patterns := args tags := "llgo,math_big_pure_go"