diff --git a/_xtool/internal/clang/clang_test.go b/_xtool/internal/clang/clang_test.go index 23a02dfc..11ca959f 100644 --- a/_xtool/internal/clang/clang_test.go +++ b/_xtool/internal/clang/clang_test.go @@ -3,15 +3,11 @@ package clang_test import ( "fmt" "os" - "path" - "path/filepath" "strings" "testing" - "github.com/goplus/lib/c" "github.com/goplus/lib/c/clang" clangutils "github.com/goplus/llcppg/_xtool/internal/clang" - "github.com/goplus/llcppg/_xtool/internal/clangtool" ) func TestClangUtil(t *testing.T) { @@ -179,75 +175,6 @@ cursorRange 11:1 -> 11:11 compareOutput(t, expect, str.String()) } -func TestPreprocess(t *testing.T) { - outfile, err := os.CreateTemp("", "compose_*.h") - if err != nil { - panic(err) - } - absPath, err := filepath.Abs("./testdata/hfile") - if err != nil { - panic(err) - } - clangtool.ComposeIncludes([]string{"main.h", "compat.h"}, outfile.Name()) - - efile, err := os.CreateTemp("", "temp_*.i") - if err != nil { - panic(err) - } - defer os.Remove(efile.Name()) - - cfg := &clangtool.PreprocessConfig{ - File: outfile.Name(), - IsCpp: true, - Args: []string{"-I" + absPath}, - OutFile: efile.Name(), - } - err = clangtool.Preprocess(cfg) - if err != nil { - panic(err) - } - config := &clangutils.Config{ - File: efile.Name(), - Temp: false, - IsCpp: false, - } - - var str strings.Builder - - visit(config, func(cursor, parent clang.Cursor) clang.ChildVisitResult { - switch cursor.Kind { - case clang.CursorEnumDecl, clang.CursorStructDecl, clang.CursorUnionDecl, clang.CursorTypedefDecl: - var filename clang.String - var line, column c.Uint - cursor.Location().PresumedLocation(&filename, &line, &column) - str.WriteString("TypeKind: ") - str.WriteString(clang.GoString(cursor.Kind.String())) - str.WriteString(" Name: ") - str.WriteString(clang.GoString(cursor.String())) - str.WriteString("\n") - str.WriteString("Location: ") - str.WriteString(fmt.Sprintf("%s:%d:%d\n", path.Base(c.GoString(filename.CStr())), line, column)) - } - return clang.ChildVisit_Continue - }) - - expect := ` -TypeKind: StructDecl Name: A -Location: main.h:3:16 -TypeKind: TypedefDecl Name: A -Location: main.h:6:3 -TypeKind: TypedefDecl Name: B -Location: compat.h:3:11 -TypeKind: TypedefDecl Name: C -Location: main.h:8:11 -` - - compareOutput(t, expect, str.String()) - - outfile.Close() - os.Remove(outfile.Name()) -} - func visit(config *clangutils.Config, visitFunc func(cursor, parent clang.Cursor) clang.ChildVisitResult) { index, unit, err := clangutils.CreateTranslationUnit(config) if err != nil { diff --git a/_xtool/internal/clangtool/clangtool.go b/_xtool/internal/clangtool/clangtool.go index daecd9da..64ac8c54 100644 --- a/_xtool/internal/clangtool/clangtool.go +++ b/_xtool/internal/clangtool/clangtool.go @@ -15,25 +15,6 @@ var _sysRootDirOnce = sync.OnceValues(sysRoot) var _matchISysrootRegex = regexp.MustCompile(`-(resource-dir|internal-isystem|isysroot|internal-externc-isystem)\s(\S+)`) -type PreprocessConfig struct { - File string - IsCpp bool - Args []string - OutFile string -} - -func Preprocess(cfg *PreprocessConfig) error { - args := []string{"-E"} - args = append(args, defaultArgs(cfg.IsCpp)...) - args = append(args, cfg.Args...) - args = append(args, cfg.File) - args = append(args, "-o", cfg.OutFile) - cmd := exec.Command("clang", args...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() -} - // ComposeIncludes create Include list // #include // #include diff --git a/_xtool/internal/clang/testdata/hfile/compat.h b/_xtool/internal/parser/_testdata/hfile/compat.h similarity index 100% rename from _xtool/internal/clang/testdata/hfile/compat.h rename to _xtool/internal/parser/_testdata/hfile/compat.h diff --git a/_xtool/internal/clang/testdata/hfile/main.h b/_xtool/internal/parser/_testdata/hfile/main.h similarity index 100% rename from _xtool/internal/clang/testdata/hfile/main.h rename to _xtool/internal/parser/_testdata/hfile/main.h diff --git a/_xtool/internal/parser/parser_test.go b/_xtool/internal/parser/parser_test.go index 1e5d5f9d..420df8f4 100644 --- a/_xtool/internal/parser/parser_test.go +++ b/_xtool/internal/parser/parser_test.go @@ -4,16 +4,19 @@ import ( "encoding/json" "fmt" "os" + "path" "path/filepath" "reflect" + "strings" "testing" "github.com/goplus/lib/c" "github.com/goplus/lib/c/clang" clangutils "github.com/goplus/llcppg/_xtool/internal/clang" + "github.com/goplus/llcppg/_xtool/internal/clangtool" "github.com/goplus/llcppg/_xtool/internal/parser" - "github.com/goplus/llcppg/ast" + "github.com/goplus/llgo/xtool/clang/preprocessor" ) func TestParser(t *testing.T) { @@ -533,3 +536,85 @@ func getComplexType(flag ast.TypeFlag) clang.Type { return typ } + +func TestPreprocess(t *testing.T) { + combinedFile, err := os.CreateTemp("./", "compose_*.h") + if err != nil { + panic(err) + } + defer os.Remove(combinedFile.Name()) + + clangtool.ComposeIncludes([]string{"main.h", "compat.h"}, combinedFile.Name()) + + efile, err := os.CreateTemp("", "temp_*.i") + if err != nil { + panic(err) + } + defer os.Remove(efile.Name()) + + ppconf := &preprocessor.Config{ + Compiler: "clang", + Flags: []string{"-I./_testdata/hfile"}, + } + err = preprocessor.Do(combinedFile.Name(), efile.Name(), ppconf) + if err != nil { + t.Fatal(err) + } + + config := &clangutils.Config{ + File: efile.Name(), + Temp: false, + IsCpp: false, + } + + var str strings.Builder + + visit(config, func(cursor, parent clang.Cursor) clang.ChildVisitResult { + switch cursor.Kind { + case clang.CursorEnumDecl, clang.CursorStructDecl, clang.CursorUnionDecl, clang.CursorTypedefDecl: + var filename clang.String + var line, column c.Uint + cursor.Location().PresumedLocation(&filename, &line, &column) + str.WriteString("TypeKind: ") + str.WriteString(clang.GoString(cursor.Kind.String())) + str.WriteString(" Name: ") + str.WriteString(clang.GoString(cursor.String())) + str.WriteString("\n") + str.WriteString("Location: ") + str.WriteString(fmt.Sprintf("%s:%d:%d\n", path.Base(c.GoString(filename.CStr())), line, column)) + } + return clang.ChildVisit_Continue + }) + + expect := ` +TypeKind: StructDecl Name: A +Location: main.h:3:16 +TypeKind: TypedefDecl Name: A +Location: main.h:6:3 +TypeKind: TypedefDecl Name: B +Location: compat.h:3:11 +TypeKind: TypedefDecl Name: C +Location: main.h:8:11 +` + + compareOutput(t, expect, str.String()) +} + +func visit(config *clangutils.Config, visitFunc func(cursor, parent clang.Cursor) clang.ChildVisitResult) { + index, unit, err := clangutils.CreateTranslationUnit(config) + if err != nil { + panic(err) + } + cursor := unit.Cursor() + clangutils.VisitChildren(cursor, visitFunc) + index.Dispose() + unit.Dispose() +} + +func compareOutput(t *testing.T, expected, actual string) { + expected = strings.TrimSpace(expected) + actual = strings.TrimSpace(actual) + if expected != actual { + t.Fatalf("Test failed: expected \n%s \ngot \n%s", expected, actual) + } +} diff --git a/_xtool/llcppsigfetch/internal/parse/parse.go b/_xtool/llcppsigfetch/internal/parse/parse.go index 3fb8cc81..ea221f41 100644 --- a/_xtool/llcppsigfetch/internal/parse/parse.go +++ b/_xtool/llcppsigfetch/internal/parse/parse.go @@ -10,6 +10,7 @@ import ( "github.com/goplus/llcppg/_xtool/internal/config" "github.com/goplus/llcppg/_xtool/internal/parser" llcppg "github.com/goplus/llcppg/config" + "github.com/goplus/llgo/xtool/clang/preprocessor" ) type dbgFlags = int @@ -79,16 +80,32 @@ func Do(conf *Config) error { // prepare clang flags to preprocess the combined file clangFlags := strings.Fields(conf.Conf.CFlags) + if !isCpp { + clangFlags = append(clangFlags, "-x", "c") + } else { + clangFlags = append(clangFlags, "-x", "c++") + } clangFlags = append(clangFlags, "-C") // keep comment clangFlags = append(clangFlags, "-dD") // keep macro clangFlags = append(clangFlags, "-fparse-all-comments") - err = clangtool.Preprocess(&clangtool.PreprocessConfig{ - File: conf.CombinedFile, - IsCpp: isCpp, - Args: clangFlags, - OutFile: conf.PreprocessedFile, - }) + pwd, err := os.Getwd() + if err != nil { + return err + } + + ppconf := &preprocessor.Config{ + Compiler: "clang", + Flags: clangFlags, + BaseDir: pwd, + } + + fmt.Fprintln(os.Stderr, "pwd", pwd) + fmt.Fprintln(os.Stderr, "clangFlags", clangFlags) + fmt.Fprintln(os.Stderr, "conf.CombinedFile", conf.CombinedFile) + fmt.Fprintln(os.Stderr, "conf.PreprocessedFile", conf.PreprocessedFile) + + err = preprocessor.Do(conf.CombinedFile, conf.PreprocessedFile, ppconf) if err != nil { return err } diff --git a/_xtool/llcppsigfetch/internal/parse/parse_test.go b/_xtool/llcppsigfetch/internal/parse/parse_test.go index 095fe363..42796806 100644 --- a/_xtool/llcppsigfetch/internal/parse/parse_test.go +++ b/_xtool/llcppsigfetch/internal/parse/parse_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/goplus/llcppg/_xtool/internal/clangtool" "github.com/goplus/llcppg/_xtool/internal/parser" "github.com/goplus/llcppg/_xtool/llcppsigfetch/internal/parse" llcppg "github.com/goplus/llcppg/config" @@ -27,7 +28,11 @@ func TestInclusionMap(t *testing.T) { t.Fatalf("sys/types.h not found") } } + + combinedFile := createCombineFile([]string{"sys.h"}) + defer os.Remove(combinedFile) err := parse.Do(&parse.Config{ + CombinedFile: combinedFile, Conf: &llcppg.Config{ Include: []string{"sys.h"}, CFlags: "-I./testdata/sysinc/hfile", @@ -48,7 +53,10 @@ func TestSystemHeader(t *testing.T) { } } } + combinedFile := createCombineFile([]string{"inc.h"}) + defer os.Remove(combinedFile) err := parse.Do(&parse.Config{ + CombinedFile: combinedFile, Conf: &llcppg.Config{ Include: []string{"inc.h"}, CFlags: "-I./testdata/sysinc/hfile", @@ -61,7 +69,10 @@ func TestSystemHeader(t *testing.T) { } func TestMacroExpansionOtherFile(t *testing.T) { + combinedFile := createCombineFile([]string{"ref.h"}) + defer os.Remove(combinedFile) conf := &parse.Config{ + CombinedFile: combinedFile, Conf: &llcppg.Config{ Include: []string{"ref.h"}, CFlags: "-I./testdata/macroexpan/hfile", @@ -125,3 +136,15 @@ func marshalFileMap(fmap map[string]*llcppg.FileInfo) map[string]any { } return root } + +func createCombineFile(includes []string) string { + combinedFile, err := os.CreateTemp("./", "compose_*.h") + if err != nil { + panic(err) + } + err = clangtool.ComposeIncludes(includes, combinedFile.Name()) + if err != nil { + panic(err) + } + return combinedFile.Name() +}