mirror of
https://github.com/mappu/miqt.git
synced 2024-12-22 00:48:38 +00:00
genbindings/main: support custom clang ast node matchers
This commit is contained in:
parent
20f6d7878b
commit
d639160886
@ -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
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user