From d6391608861e45bbf188700468704101613f92b0 Mon Sep 17 00:00:00 2001 From: mappu Date: Sun, 20 Oct 2024 17:58:00 +1300 Subject: [PATCH] genbindings/main: support custom clang ast node matchers --- cmd/genbindings/clangexec.go | 47 ++++++++++++++++++++++++------------ cmd/genbindings/main.go | 10 +++++--- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/cmd/genbindings/clangexec.go b/cmd/genbindings/clangexec.go index 5a105af6..e1162d2d 100644 --- a/cmd/genbindings/clangexec.go +++ b/cmd/genbindings/clangexec.go @@ -9,6 +9,7 @@ import ( "log" "os" "os/exec" + "strings" "sync" "time" ) @@ -18,7 +19,26 @@ const ( ClangRetryDelay = 3 * time.Second ) -func clangExec(ctx context.Context, clangBin, inputHeader string, cflags []string) ([]interface{}, error) { +type ClangMatcher func(astNodeFilename string) bool + +func ClangMatchSameHeaderDefinitionOnly(astNodeFilename string) bool { + return astNodeFilename == "" +} + +type clangMatchUnderPath struct { + basePath string +} + +func (c *clangMatchUnderPath) Match(astNodeFilename string) bool { + if astNodeFilename == "" { + return true + } + return strings.HasPrefix(astNodeFilename, c.basePath) +} + +// + +func clangExec(ctx context.Context, clangBin, inputHeader string, cflags []string, matcher ClangMatcher) ([]interface{}, error) { clangArgs := []string{`-x`, `c++`} clangArgs = append(clangArgs, cflags...) @@ -44,7 +64,7 @@ func clangExec(ctx context.Context, clangBin, inputHeader string, cflags []strin wg.Add(1) go func() { defer wg.Done() - inner, innerErr = clangStripUpToFile(pr, inputHeader) + inner, innerErr = clangStripUpToFile(pr, matcher) }() err = cmd.Wait() @@ -57,10 +77,10 @@ func clangExec(ctx context.Context, clangBin, inputHeader string, cflags []strin return inner, innerErr } -func mustClangExec(ctx context.Context, clangBin, inputHeader string, cflags []string) []interface{} { +func mustClangExec(ctx context.Context, clangBin, inputHeader string, cflags []string, matcher ClangMatcher) []interface{} { for i := 0; i < ClangMaxRetries; i++ { - astInner, err := clangExec(ctx, clangBin, inputHeader, cflags) + astInner, err := clangExec(ctx, clangBin, inputHeader, cflags, matcher) if err != nil { // Log and continue with next retry log.Printf("WARNING: Clang execution failed: %v", err) @@ -83,7 +103,7 @@ func mustClangExec(ctx context.Context, clangBin, inputHeader string, cflags []s // This cleans out everything in the translation unit that came from an // #included file. // @ref https://stackoverflow.com/a/71128654 -func clangStripUpToFile(stdout io.Reader, inputFilePath string) ([]interface{}, error) { +func clangStripUpToFile(stdout io.Reader, matcher ClangMatcher) ([]interface{}, error) { var obj = map[string]interface{}{} err := json.NewDecoder(stdout).Decode(&obj) @@ -108,10 +128,8 @@ func clangStripUpToFile(stdout io.Reader, inputFilePath string) ([]interface{}, return nil, errors.New("entry is not a map") } - if _, ok := entry["isImplicit"]; ok { - // Don't keep - continue - } + // Check where this AST node came from, if it was directly written + // in this header or if it as part of an #include var match_filename = "" @@ -140,16 +158,13 @@ func clangStripUpToFile(stdout io.Reader, inputFilePath string) ([]interface{}, // log.Printf("# name=%v kind=%v filename=%q\n", entry["name"], entry["kind"], match_filename) - if match_filename == "" { + if matcher(match_filename) { // Keep ret = append(ret, entry) - - } else if match_filename != inputFilePath { - // Skip this - } else { - // Keep this - // ret = append(ret, entry) } + + // Otherwise, discard this AST node, it comes from some imported file + // that we will likely scan separately } return ret, nil diff --git a/cmd/genbindings/main.go b/cmd/genbindings/main.go index f2abbd5c..3e332255 100644 --- a/cmd/genbindings/main.go +++ b/cmd/genbindings/main.go @@ -113,6 +113,7 @@ func main() { *clang, strings.Fields(pkgConfigCflags("Qt5Widgets")), filepath.Join(*outDir, "qt"), + ClangMatchSameHeaderDefinitionOnly, ) generate( @@ -123,10 +124,11 @@ func main() { *clang, strings.Fields(pkgConfigCflags("Qt5PrintSupport")), filepath.Join(*outDir, "qt/qprintsupport"), + ClangMatchSameHeaderDefinitionOnly, ) } -func generate(packageName string, srcDirs []string, clangBin string, cflags []string, outDir string) { +func generate(packageName string, srcDirs []string, clangBin string, cflags []string, outDir string, matcher ClangMatcher) { var includeFiles []string for _, srcDir := range srcDirs { @@ -152,7 +154,7 @@ func generate(packageName string, srcDirs []string, clangBin string, cflags []st // PASS 0 (Fill clang cache) // - generateClangCaches(includeFiles, clangBin, cflags) + generateClangCaches(includeFiles, clangBin, cflags, matcher) // The cache should now be fully populated. @@ -279,7 +281,7 @@ func generate(packageName string, srcDirs []string, clangBin string, cflags []st log.Printf("Processing %d file(s) completed", len(includeFiles)) } -func generateClangCaches(includeFiles []string, clangBin string, cflags []string) { +func generateClangCaches(includeFiles []string, clangBin string, cflags []string, matcher ClangMatcher) { var clangChan = make(chan string, 0) var clangWg sync.WaitGroup @@ -301,7 +303,7 @@ func generateClangCaches(includeFiles []string, clangBin string, cflags []string // Parse the file // This seems to intermittently fail, so allow retrying - astInner := mustClangExec(ctx, clangBin, inputHeader, cflags) + astInner := mustClangExec(ctx, clangBin, inputHeader, cflags, matcher) // Write to cache jb, err := json.MarshalIndent(astInner, "", "\t")