cgo: support macros
This commit is contained in:
@@ -88,18 +88,18 @@ func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs map[string
|
||||
cgoLdflags = append(cgoLdflags, linkFile)
|
||||
}, verbose)
|
||||
}
|
||||
re := regexp.MustCompile(`^(_cgo_[^_]+_Cfunc_)(.*)$`)
|
||||
cgoFuncs := make(map[string]string)
|
||||
re := regexp.MustCompile(`^(_cgo_[^_]+_(Cfunc|Cmacro)_)(.*)$`)
|
||||
cgoSymbols := make(map[string]string)
|
||||
mallocFix := false
|
||||
for _, funcs := range externs {
|
||||
for _, funcName := range funcs {
|
||||
if m := re.FindStringSubmatch(funcName); len(m) > 0 {
|
||||
cgoFuncs[funcName] = m[2]
|
||||
for _, symbols := range externs {
|
||||
for _, symbolName := range symbols {
|
||||
if m := re.FindStringSubmatch(symbolName); len(m) > 0 {
|
||||
cgoSymbols[symbolName] = m[3]
|
||||
pkgPrefix := m[1]
|
||||
// fix missing _cgo_9113e32b6599_Cfunc__Cmalloc
|
||||
if !mallocFix {
|
||||
pkgPrefix := m[1]
|
||||
if !mallocFix && m[2] == "Cfunc" {
|
||||
mallocName := pkgPrefix + "_Cmalloc"
|
||||
cgoFuncs[mallocName] = "_Cmalloc"
|
||||
cgoSymbols[mallocName] = "_Cmalloc"
|
||||
mallocFix = true
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,10 @@ func buildCgo(ctx *context, pkg *aPackage, files []*ast.File, externs map[string
|
||||
tmpName := tmpFile.Name()
|
||||
defer os.Remove(tmpName)
|
||||
code := cgoHeader + "\n\n" + preamble.src
|
||||
externDecls := genExternDeclsByClang(code, cflags, cgoFuncs)
|
||||
externDecls, err := genExternDeclsByClang(code, cflags, cgoSymbols)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = os.WriteFile(tmpName, []byte(code+"\n\n"+externDecls), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -134,42 +137,90 @@ type clangASTNode struct {
|
||||
Inner []clangASTNode `json:"inner,omitempty"`
|
||||
}
|
||||
|
||||
func genExternDeclsByClang(src string, cflags []string, cgoFuncs map[string]string) string {
|
||||
func genExternDeclsByClang(src string, cflags []string, cgoSymbols map[string]string) (string, error) {
|
||||
tmpSrc, err := os.CreateTemp("", "cgo-src-*.c")
|
||||
if err != nil {
|
||||
return ""
|
||||
return "", err
|
||||
}
|
||||
defer os.Remove(tmpSrc.Name())
|
||||
if err := os.WriteFile(tmpSrc.Name(), []byte(src), 0644); err != nil {
|
||||
return ""
|
||||
return "", err
|
||||
}
|
||||
args := append([]string{"-Xclang", "-ast-dump=json", "-fsyntax-only"}, cflags...)
|
||||
args = append(args, tmpSrc.Name())
|
||||
cmd := exec.Command("clang", args...)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
symbolNames := make(map[string]bool)
|
||||
if err := getFuncNames(tmpSrc.Name(), cflags, symbolNames); err != nil {
|
||||
return "", err
|
||||
}
|
||||
var astRoot clangASTNode
|
||||
if err := json.Unmarshal(output, &astRoot); err != nil {
|
||||
return ""
|
||||
macroNames := make(map[string]bool)
|
||||
if err := getMacroNames(tmpSrc.Name(), cflags, macroNames); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
funcNames := make(map[string]bool)
|
||||
extractFuncNames(&astRoot, funcNames)
|
||||
|
||||
b := strings.Builder{}
|
||||
var toRemove []string
|
||||
for cgoFunc, funcName := range cgoFuncs {
|
||||
if funcNames[funcName] {
|
||||
b.WriteString(fmt.Sprintf("void* %s = (void*)%s;\n", cgoFunc, funcName))
|
||||
toRemove = append(toRemove, cgoFunc)
|
||||
for cgoName, symbolName := range cgoSymbols {
|
||||
if symbolNames[symbolName] {
|
||||
b.WriteString(fmt.Sprintf("void* %s = (void*)%s;\n", cgoName, symbolName))
|
||||
toRemove = append(toRemove, cgoName)
|
||||
} else if macroNames[symbolName] {
|
||||
/* template:
|
||||
typeof(stdout) _cgo_1574167f3838_Cmacro_stdout;
|
||||
|
||||
__attribute__((constructor))
|
||||
static void _init__cgo_1574167f3838_Cmacro_stdout() {
|
||||
_cgo_1574167f3838_Cmacro_stdout = stdout;
|
||||
}*/
|
||||
b.WriteString(fmt.Sprintf(`
|
||||
typeof(%s) %s;
|
||||
|
||||
__attribute__((constructor))
|
||||
static void _init_%s() {
|
||||
%s = %s;
|
||||
}
|
||||
`, symbolName, cgoName, cgoName, cgoName, symbolName))
|
||||
toRemove = append(toRemove, cgoName)
|
||||
}
|
||||
}
|
||||
for _, funcName := range toRemove {
|
||||
delete(cgoFuncs, funcName)
|
||||
delete(cgoSymbols, funcName)
|
||||
}
|
||||
return b.String()
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
func getMacroNames(file string, cflags []string, macroNames map[string]bool) error {
|
||||
args := append([]string{"-dM", "-E"}, cflags...)
|
||||
args = append(args, file)
|
||||
cmd := exec.Command("clang", args...)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, line := range strings.Split(string(output), "\n") {
|
||||
if strings.HasPrefix(line, "#define ") {
|
||||
define := strings.TrimPrefix(line, "#define ")
|
||||
parts := strings.SplitN(define, " ", 2)
|
||||
if len(parts) > 1 {
|
||||
macroNames[parts[0]] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getFuncNames(file string, cflags []string, symbolNames map[string]bool) error {
|
||||
args := append([]string{"-Xclang", "-ast-dump=json", "-fsyntax-only"}, cflags...)
|
||||
args = append(args, file)
|
||||
cmd := exec.Command("clang", args...)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var astRoot clangASTNode
|
||||
if err := json.Unmarshal(output, &astRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
extractFuncNames(&astRoot, symbolNames)
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractFuncNames(node *clangASTNode, funcNames map[string]bool) {
|
||||
|
||||
Reference in New Issue
Block a user