From 7753f01cd3053b171c66122ec6110f54d06bcdfd Mon Sep 17 00:00:00 2001 From: luoliwoshang <2643523683@qq.com> Date: Fri, 18 Oct 2024 11:25:53 +0800 Subject: [PATCH] llcppsymg:libs,cflags parse --- .../llcppsymg/_cmptest/config_test/config.go | 269 ++++++++++++++++++ .../_cmptest/config_test/llgo.expect | 73 +++++ .../llcppsymg/_cmptest/parse_test/llgo.expect | 18 -- .../llcppsymg/_cmptest/parse_test/parse.go | 61 ---- .../_cmptest/symbol_test/llgo.expect | 31 -- .../llcppsymg/_cmptest/symbol_test/symbol.go | 150 ---------- .../_xtool/llcppsymg/config/cfgparse/parse.go | 109 +++++++ chore/_xtool/llcppsymg/llcppsymg.go | 9 +- chore/_xtool/llcppsymg/parse/parse.go | 37 --- chore/_xtool/llcppsymg/symbol/symbol.go | 88 ++---- 10 files changed, 477 insertions(+), 368 deletions(-) create mode 100644 chore/_xtool/llcppsymg/config/cfgparse/parse.go diff --git a/chore/_xtool/llcppsymg/_cmptest/config_test/config.go b/chore/_xtool/llcppsymg/_cmptest/config_test/config.go index 6ef2e2d1d..4b3bdbc12 100644 --- a/chore/_xtool/llcppsymg/_cmptest/config_test/config.go +++ b/chore/_xtool/llcppsymg/_cmptest/config_test/config.go @@ -2,13 +2,21 @@ package main import ( "fmt" + "os" + "path/filepath" + "runtime" "strings" "github.com/goplus/llgo/chore/_xtool/llcppsymg/config" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/config/cfgparse" ) func main() { TestGetConf() + TestParseLibs() + TestGenDylibPaths() + TestParseCFlags() + TestGenHeaderFilePath() } func TestGetConf() { @@ -61,3 +69,264 @@ func TestGetConf() { fmt.Println() } } + +func TestParseLibs() { + fmt.Println("=== Test ParseLibs ===") + + testCases := []struct { + name string + input string + }{ + { + name: "Lua library", + input: "-L/opt/homebrew/lib -llua -lm", + }, + { + name: "SQLite library", + input: "-L/opt/homebrew/opt/sqlite/lib -lsqlite3", + }, + { + name: "INIReader library", + input: "-L/opt/homebrew/Cellar/inih/58/lib -lINIReader", + }, + { + name: "Multiple library paths", + input: "-L/opt/homebrew/lib -L/usr/lib -llua", + }, + { + name: "No valid library", + input: "-L/opt/homebrew/lib", + }, + } + + for _, tc := range testCases { + fmt.Printf("Test case: %s\n", tc.name) + fmt.Printf("Input: %s\n", tc.input) + + conf := cfgparse.ParseLibs(tc.input) + + fmt.Println("Paths:", conf.Paths) + fmt.Println("Names:", conf.Names) + } +} + +func TestGenDylibPaths() { + fmt.Println("=== Test GenDylibPaths ===") + + tempDir := os.TempDir() + tempDefaultPath := filepath.Join(tempDir, "symblib") + affix := ".dylib" + if runtime.GOOS == "linux" { + affix = ".so" + } + err := os.MkdirAll(tempDefaultPath, 0755) + if err != nil { + fmt.Printf("Failed to create temp default path: %v\n", err) + return + } + + dylib1 := filepath.Join(tempDir, "libsymb1"+affix) + dylib2 := filepath.Join(tempDir, "libsymb2"+affix) + defaultDylib3 := filepath.Join(tempDefaultPath, "libsymb3"+affix) + + os.Create(dylib1) + os.Create(dylib2) + os.Create(defaultDylib3) + defer os.Remove(dylib1) + defer os.Remove(dylib2) + defer os.Remove(defaultDylib3) + defer os.Remove(tempDefaultPath) + + testCase := []struct { + name string + conf *cfgparse.Libs + defaultPaths []string + want []string + }{ + { + name: "existing dylib", + conf: &cfgparse.Libs{ + Names: []string{"symb1"}, + Paths: []string{tempDir}, + }, + defaultPaths: []string{}, + want: []string{dylib1}, + }, + { + name: "existing dylibs", + conf: &cfgparse.Libs{ + Names: []string{"symb1", "symb2"}, + Paths: []string{tempDir}, + }, + defaultPaths: []string{}, + want: []string{dylib1, dylib2}, + }, + { + name: "existint default paths", + conf: &cfgparse.Libs{ + Names: []string{"symb1", "symb3"}, + Paths: []string{tempDir}, + }, + defaultPaths: []string{tempDefaultPath}, + want: []string{dylib1, defaultDylib3}, + }, + { + name: "existint default paths & not found", + conf: &cfgparse.Libs{ + Names: []string{"symb1", "symb3", "math"}, + Paths: []string{tempDir}, + }, + defaultPaths: []string{tempDefaultPath}, + want: []string{dylib1, defaultDylib3}, + }, + { + name: "no existing dylib", + conf: &cfgparse.Libs{ + Names: []string{"notexist"}, + Paths: []string{tempDir}, + }, + want: []string{}, + }, + } + for _, tc := range testCase { + fmt.Printf("Test case: %s\n", tc.name) + paths, notFounds, err := tc.conf.GenDylibPaths(tc.defaultPaths) + + if len(notFounds) > 0 { + fmt.Println("notFounds", notFounds) + } + + if err != nil { + fmt.Printf("Error: %v\n", err) + } + + for _, path := range paths { + found := false + for _, wantPath := range tc.want { + if path == wantPath { + found = true + fileName := filepath.Base(path) + if runtime.GOOS == "linux" { + fileName = strings.TrimSuffix(fileName, ".so") + } else { + fileName = strings.TrimSuffix(fileName, ".dylib") + } + fmt.Printf("Path %s is in the expected paths\n", fileName) + break + } + } + if !found { + fmt.Printf("Path %s is not in the expected paths\n", path) + } + } + + } +} + +func TestParseCFlags() { + fmt.Println("=== Test ParseCFlags ===") + + testCases := []struct { + name string + input string + }{ + { + name: "Single include path", + input: "-I/usr/include", + }, + { + name: "Multiple include paths", + input: "-I/usr/include -I/opt/homebrew/include", + }, + { + name: "Include paths mixed with other flags", + input: "-I/usr/include -DDEBUG -I/opt/local/include -Wall", + }, + { + name: "Empty input", + input: "", + }, + } + + for _, tc := range testCases { + fmt.Printf("Test case: %s\n", tc.name) + fmt.Printf("Input: %s\n", tc.input) + + conf := cfgparse.ParseCFlags(tc.input) + + fmt.Println("Paths:", conf.Paths) + } +} + +func TestGenHeaderFilePath() { + fmt.Println("=== Test GenHeaderFilePath ===") + + tempDir := os.TempDir() + temDir2 := filepath.Join(tempDir, "include") + tempFile1 := filepath.Join(tempDir, "test1.h") + tempFile2 := filepath.Join(tempDir, "test2.h") + tempFile3 := filepath.Join(temDir2, "test3.h") + os.MkdirAll(temDir2, 0755) + os.Create(tempFile1) + os.Create(tempFile2) + os.Create(tempFile3) + defer os.Remove(tempFile1) + defer os.Remove(tempFile2) + defer os.Remove(tempFile3) + defer os.Remove(temDir2) + + testCases := []struct { + name string + cflags string + files []string + }{ + { + name: "Valid files", + cflags: "-I" + tempDir, + files: []string{"test1.h", "test2.h"}, + }, + { + name: "Mixed existing and non-existing files", + cflags: "-I" + tempDir, + files: []string{"test1.h", "nonexistent.h"}, + }, + { + name: "Multiple include paths", + cflags: "-I" + tempDir + " -I" + temDir2, + files: []string{"test1.h", "test2.h", "test3.h"}, + }, + { + name: "No existing files", + cflags: "-I" + tempDir, + files: []string{"nonexistent1.h", "nonexistent2.h"}, + }, + { + name: "Empty file list", + cflags: "-I/usr/include", + files: []string{}, + }, + } + + for _, tc := range testCases { + fmt.Printf("Test case: %s\n", tc.name) + fmt.Printf("Input files: %v\n", tc.files) + + cflag := cfgparse.ParseCFlags(tc.cflags) + result, notFounds, err := cflag.GenHeaderFilePaths(tc.files) + + if err != nil { + fmt.Printf("Error: %v\n", err) + } + if len(notFounds) > 0 { + fmt.Println("notFounds", notFounds) + } + if result != nil { + relativeResult := make([]string, len(result)) + for i, path := range result { + relativeResult[i] = filepath.Base(path) + } + fmt.Printf("Output: %v\n", relativeResult) + } + fmt.Println() + } +} diff --git a/chore/_xtool/llcppsymg/_cmptest/config_test/llgo.expect b/chore/_xtool/llcppsymg/_cmptest/config_test/llgo.expect index acbf814f4..a7c57a055 100644 --- a/chore/_xtool/llcppsymg/_cmptest/config_test/llgo.expect +++ b/chore/_xtool/llcppsymg/_cmptest/config_test/llgo.expect @@ -18,6 +18,79 @@ Cplusplus: false === Test case: Invalid JSON === Error: failed to parse config +=== Test ParseLibs === +Test case: Lua library +Input: -L/opt/homebrew/lib -llua -lm +Paths: [/opt/homebrew/lib] +Names: [lua m] +Test case: SQLite library +Input: -L/opt/homebrew/opt/sqlite/lib -lsqlite3 +Paths: [/opt/homebrew/opt/sqlite/lib] +Names: [sqlite3] +Test case: INIReader library +Input: -L/opt/homebrew/Cellar/inih/58/lib -lINIReader +Paths: [/opt/homebrew/Cellar/inih/58/lib] +Names: [INIReader] +Test case: Multiple library paths +Input: -L/opt/homebrew/lib -L/usr/lib -llua +Paths: [/opt/homebrew/lib /usr/lib] +Names: [lua] +Test case: No valid library +Input: -L/opt/homebrew/lib +Paths: [/opt/homebrew/lib] +Names: [] +=== Test GenDylibPaths === +Test case: existing dylib +Path libsymb1 is in the expected paths +Test case: existing dylibs +Path libsymb1 is in the expected paths +Path libsymb2 is in the expected paths +Test case: existint default paths +Path libsymb1 is in the expected paths +Path libsymb3 is in the expected paths +Test case: existint default paths & not found +notFounds [math] +Path libsymb1 is in the expected paths +Path libsymb3 is in the expected paths +Test case: no existing dylib +notFounds [notexist] +Error: failed to find any libraries +=== Test ParseCFlags === +Test case: Single include path +Input: -I/usr/include +Paths: [/usr/include] +Test case: Multiple include paths +Input: -I/usr/include -I/opt/homebrew/include +Paths: [/usr/include /opt/homebrew/include] +Test case: Include paths mixed with other flags +Input: -I/usr/include -DDEBUG -I/opt/local/include -Wall +Paths: [/usr/include /opt/local/include] +Test case: Empty input +Input: +Paths: [] +=== Test GenHeaderFilePath === +Test case: Valid files +Input files: [test1.h test2.h] +Output: [test1.h test2.h] + +Test case: Mixed existing and non-existing files +Input files: [test1.h nonexistent.h] +notFounds [nonexistent.h] +Output: [test1.h] + +Test case: Multiple include paths +Input files: [test1.h test2.h test3.h] +Output: [test1.h test2.h test3.h] + +Test case: No existing files +Input files: [nonexistent1.h nonexistent2.h] +Error: failed to find any header files +notFounds [nonexistent1.h nonexistent2.h] + +Test case: Empty file list +Input files: [] +Error: failed to find any header files + #stderr diff --git a/chore/_xtool/llcppsymg/_cmptest/parse_test/llgo.expect b/chore/_xtool/llcppsymg/_cmptest/parse_test/llgo.expect index 3dff278d1..5f2827564 100644 --- a/chore/_xtool/llcppsymg/_cmptest/parse_test/llgo.expect +++ b/chore/_xtool/llcppsymg/_cmptest/parse_test/llgo.expect @@ -1,22 +1,4 @@ #stdout -=== Test GenHeaderFilePath === -Test case: Valid files -Input files: [test1.h test2.h] -Output: [test1.h test2.h] - -Test case: Mixed existing and non-existing files -Input files: [test1.h nonexistent.h] -Error: some files not found or inaccessible: [file not found: nonexistent.h] -Output: [test1.h] - -Test case: No existing files -Input files: [nonexistent1.h nonexistent2.h] -Error: some files not found or inaccessible: [file not found: nonexistent1.h file not found: nonexistent2.h] - -Test case: Empty file list -Input files: [] -Error: no valid header files - === Test NewSymbolProcessor === Before: No prefixes After: Prefixes: [lua_ luaL_] diff --git a/chore/_xtool/llcppsymg/_cmptest/parse_test/parse.go b/chore/_xtool/llcppsymg/_cmptest/parse_test/parse.go index 0f738594f..4a827b453 100644 --- a/chore/_xtool/llcppsymg/_cmptest/parse_test/parse.go +++ b/chore/_xtool/llcppsymg/_cmptest/parse_test/parse.go @@ -2,15 +2,12 @@ package main import ( "fmt" - "os" - "path/filepath" "sort" "github.com/goplus/llgo/chore/_xtool/llcppsymg/parse" ) func main() { - TestGenHeaderFilePath() TestNewSymbolProcessor() TestRemovePrefix() TestToGoName() @@ -19,64 +16,6 @@ func main() { TestParseHeaderFile() } -func TestGenHeaderFilePath() { - fmt.Println("=== Test GenHeaderFilePath ===") - - tempDir := os.TempDir() - tempFile1 := filepath.Join(tempDir, "test1.h") - tempFile2 := filepath.Join(tempDir, "test2.h") - os.Create(tempFile1) - os.Create(tempFile2) - defer os.Remove(tempFile1) - defer os.Remove(tempFile2) - - testCases := []struct { - name string - cflags string - files []string - }{ - { - name: "Valid files", - cflags: "-I" + tempDir, - files: []string{"test1.h", "test2.h"}, - }, - { - name: "Mixed existing and non-existing files", - cflags: "-I" + tempDir, - files: []string{"test1.h", "nonexistent.h"}, - }, - { - name: "No existing files", - cflags: "-I" + tempDir, - files: []string{"nonexistent1.h", "nonexistent2.h"}, - }, - { - name: "Empty file list", - cflags: "-I/usr/include", - files: []string{}, - }, - } - - for _, tc := range testCases { - fmt.Printf("Test case: %s\n", tc.name) - fmt.Printf("Input files: %v\n", tc.files) - - result, err := parse.GenHeaderFilePath(tc.cflags, tc.files) - - if err != nil { - fmt.Printf("Error: %v\n", err) - } - if result != nil { - relativeResult := make([]string, len(result)) - for i, path := range result { - relativeResult[i] = filepath.Base(path) - } - fmt.Printf("Output: %v\n", relativeResult) - } - fmt.Println() - } -} - func TestNewSymbolProcessor() { fmt.Println("=== Test NewSymbolProcessor ===") process := parse.NewSymbolProcessor([]string{"lua_", "luaL_"}) diff --git a/chore/_xtool/llcppsymg/_cmptest/symbol_test/llgo.expect b/chore/_xtool/llcppsymg/_cmptest/symbol_test/llgo.expect index 69d5c78fb..4a3299436 100644 --- a/chore/_xtool/llcppsymg/_cmptest/symbol_test/llgo.expect +++ b/chore/_xtool/llcppsymg/_cmptest/symbol_test/llgo.expect @@ -1,35 +1,4 @@ #stdout -=== Test ParseLibConfig === -Test case: Lua library -Input: -L/opt/homebrew/lib -llua -lm -Paths: [/opt/homebrew/lib] -Names: [lua m] -Test case: SQLite library -Input: -L/opt/homebrew/opt/sqlite/lib -lsqlite3 -Paths: [/opt/homebrew/opt/sqlite/lib] -Names: [sqlite3] -Test case: INIReader library -Input: -L/opt/homebrew/Cellar/inih/58/lib -lINIReader -Paths: [/opt/homebrew/Cellar/inih/58/lib] -Names: [INIReader] -Test case: Multiple library paths -Input: -L/opt/homebrew/lib -L/usr/lib -llua -Paths: [/opt/homebrew/lib /usr/lib] -Names: [lua] -Test case: No valid library -Input: -L/opt/homebrew/lib -Paths: [/opt/homebrew/lib] -Names: [] -=== Test GenDylibPaths === -Test case: existing dylib -Path libsymb1 is in the expected paths -Test case: existing dylibs -Path libsymb1 is in the expected paths -Path libsymb2 is in the expected paths -Test case: existint default paths -Path libsymb1 is in the expected paths -Path libsymb3 is in the expected paths -Test case: no existing dylib === Test GetCommonSymbols === Test Case: Lua symbols diff --git a/chore/_xtool/llcppsymg/_cmptest/symbol_test/symbol.go b/chore/_xtool/llcppsymg/_cmptest/symbol_test/symbol.go index 192f2427f..357fddd4f 100644 --- a/chore/_xtool/llcppsymg/_cmptest/symbol_test/symbol.go +++ b/chore/_xtool/llcppsymg/_cmptest/symbol_test/symbol.go @@ -3,10 +3,7 @@ package main import ( "fmt" "os" - "path/filepath" - "runtime" "sort" - "strings" "github.com/goplus/llgo/chore/_xtool/llcppsymg/parse" "github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol" @@ -15,158 +12,11 @@ import ( ) func main() { - TestParseLibConfig() - TestGenDylibPaths() TestGetCommonSymbols() TestReadExistingSymbolTable() TestGenSymbolTableData() } -func TestParseLibConfig() { - fmt.Println("=== Test ParseLibConfig ===") - testCases := []struct { - name string - input string - }{ - { - name: "Lua library", - input: "-L/opt/homebrew/lib -llua -lm", - }, - { - name: "SQLite library", - input: "-L/opt/homebrew/opt/sqlite/lib -lsqlite3", - }, - { - name: "INIReader library", - input: "-L/opt/homebrew/Cellar/inih/58/lib -lINIReader", - }, - { - name: "Multiple library paths", - input: "-L/opt/homebrew/lib -L/usr/lib -llua", - }, - { - name: "No valid library", - input: "-L/opt/homebrew/lib", - }, - } - - for _, tc := range testCases { - fmt.Printf("Test case: %s\n", tc.name) - fmt.Printf("Input: %s\n", tc.input) - - conf := symbol.ParseLibConfig(tc.input) - - fmt.Println("Paths:", conf.Paths) - fmt.Println("Names:", conf.Names) - } -} - -func TestGenDylibPaths() { - fmt.Println("=== Test GenDylibPaths ===") - - tempDir := os.TempDir() - tempDefaultPath := filepath.Join(tempDir, "symblib") - affix := ".dylib" - if runtime.GOOS == "linux" { - affix = ".so" - } - err := os.MkdirAll(tempDefaultPath, 0755) - if err != nil { - fmt.Printf("Failed to create temp default path: %v\n", err) - return - } - - dylib1 := filepath.Join(tempDir, "libsymb1"+affix) - dylib2 := filepath.Join(tempDir, "libsymb2"+affix) - defaultDylib3 := filepath.Join(tempDefaultPath, "libsymb3"+affix) - - os.Create(dylib1) - os.Create(dylib2) - os.Create(defaultDylib3) - defer os.Remove(dylib1) - defer os.Remove(dylib2) - defer os.Remove(defaultDylib3) - defer os.Remove(tempDefaultPath) - - testCase := []struct { - name string - conf *symbol.LibConfig - defaultPaths []string - want []string - wantErr bool - }{ - { - name: "existing dylib", - conf: &symbol.LibConfig{ - Names: []string{"symb1"}, - Paths: []string{tempDir}, - }, - defaultPaths: []string{}, - want: []string{dylib1}, - }, - { - name: "existing dylibs", - conf: &symbol.LibConfig{ - Names: []string{"symb1", "symb2"}, - Paths: []string{tempDir}, - }, - defaultPaths: []string{}, - want: []string{dylib1, dylib2}, - }, - { - name: "existint default paths", - conf: &symbol.LibConfig{ - Names: []string{"symb1", "symb3"}, - Paths: []string{tempDir}, - }, - defaultPaths: []string{tempDefaultPath}, - want: []string{dylib1, defaultDylib3}, - }, - { - name: "no existing dylib", - conf: &symbol.LibConfig{ - Names: []string{"notexist"}, - Paths: []string{tempDir}, - }, - want: []string{}, - wantErr: true, - }, - } - for _, tc := range testCase { - fmt.Printf("Test case: %s\n", tc.name) - paths, err := symbol.GenDylibPaths(tc.conf, tc.defaultPaths) - - if tc.wantErr { - if err == nil { - fmt.Printf("Expected error, but got nil\n") - } - } else { - if err != nil { - fmt.Printf("Unexpected error: %v\n", err) - } - for _, path := range paths { - found := false - for _, wantPath := range tc.want { - if path == wantPath { - found = true - fileName := filepath.Base(path) - if runtime.GOOS == "linux" { - fileName = strings.TrimSuffix(fileName, ".so") - } else { - fileName = strings.TrimSuffix(fileName, ".dylib") - } - fmt.Printf("Path %s is in the expected paths\n", fileName) - break - } - } - if !found { - fmt.Printf("Path %s is not in the expected paths\n", path) - } - } - } - } - -} func TestGetCommonSymbols() { fmt.Println("=== Test GetCommonSymbols ===") testCases := []struct { diff --git a/chore/_xtool/llcppsymg/config/cfgparse/parse.go b/chore/_xtool/llcppsymg/config/cfgparse/parse.go new file mode 100644 index 000000000..6bac7430c --- /dev/null +++ b/chore/_xtool/llcppsymg/config/cfgparse/parse.go @@ -0,0 +1,109 @@ +package cfgparse + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +// Note: This package is not placed under the 'config' package because 'config' +// depends on 'cjson'. The parsing of Libs and cflags is intended to be usable +// by both llgo and go, without introducing additional dependencies. + +type Libs struct { + Paths []string // Dylib Path + Names []string +} + +type CFlags struct { + Paths []string // Include Path +} + +func ParseLibs(libs string) *Libs { + parts := strings.Fields(libs) + lbs := &Libs{} + for _, part := range parts { + if strings.HasPrefix(part, "-L") { + lbs.Paths = append(lbs.Paths, part[2:]) + } else if strings.HasPrefix(part, "-l") { + lbs.Names = append(lbs.Names, part[2:]) + } + } + return lbs +} + +// searches for each library name in the provided paths and default paths, +// appending the appropriate file extension (.dylib for macOS, .so for Linux). +// +// Example: For "-L/opt/homebrew/lib -llua -lm": +// - It will search for liblua.dylib (on macOS) or liblua.so (on Linux) +// - System libs like -lm are ignored and included in notFound +// +// So error is returned if no libraries found at all. +func (l *Libs) GenDylibPaths(defaultPaths []string) ([]string, []string, error) { + var foundPaths []string + var notFound []string + affix := ".dylib" + if runtime.GOOS == "linux" { + affix = ".so" + } + searchPaths := append(l.Paths, defaultPaths...) + for _, name := range l.Names { + var foundPath string + for _, path := range searchPaths { + dylibPath := filepath.Join(path, "lib"+name+affix) + if _, err := os.Stat(dylibPath); err == nil { + foundPath = dylibPath + break + } + } + if foundPath != "" { + foundPaths = append(foundPaths, foundPath) + } else { + notFound = append(notFound, name) + } + } + if len(foundPaths) == 0 { + return nil, notFound, fmt.Errorf("failed to find any libraries") + } + return foundPaths, notFound, nil +} + +func ParseCFlags(cflags string) *CFlags { + parts := strings.Fields(cflags) + cf := &CFlags{} + for _, part := range parts { + if strings.HasPrefix(part, "-I") { + cf.Paths = append(cf.Paths, part[2:]) + } + } + return cf +} + +func (cf *CFlags) GenHeaderFilePaths(files []string) ([]string, []string, error) { + var foundPaths []string + var notFound []string + + for _, file := range files { + var found bool + for _, path := range cf.Paths { + fullPath := filepath.Join(path, file) + if _, err := os.Stat(fullPath); err == nil { + foundPaths = append(foundPaths, fullPath) + found = true + break + } + } + if !found { + notFound = append(notFound, file) + } + } + + if len(foundPaths) == 0 { + return nil, notFound, fmt.Errorf("failed to find any header files") + } + + return foundPaths, notFound, nil +} diff --git a/chore/_xtool/llcppsymg/llcppsymg.go b/chore/_xtool/llcppsymg/llcppsymg.go index 2594e90a6..f9de88d4e 100644 --- a/chore/_xtool/llcppsymg/llcppsymg.go +++ b/chore/_xtool/llcppsymg/llcppsymg.go @@ -23,6 +23,7 @@ import ( "strings" "github.com/goplus/llgo/chore/_xtool/llcppsymg/config" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/config/cfgparse" "github.com/goplus/llgo/chore/_xtool/llcppsymg/parse" "github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol" ) @@ -79,11 +80,15 @@ func main() { symbols, err := symbol.ParseDylibSymbols(conf.Libs) check(err) - filepaths, err := parse.GenHeaderFilePath(conf.CFlags, conf.Include) + cflag := cfgparse.ParseCFlags(conf.CFlags) + filepaths, notFounds, err := cflag.GenHeaderFilePaths(conf.Include) check(err) if verbose { - fmt.Println("filepaths", filepaths) + fmt.Println("header file paths", filepaths) + if len(notFounds) > 0 { + fmt.Println("not found header files", notFounds) + } } headerInfos, err := parse.ParseHeaderFile(filepaths, conf.TrimPrefixes, conf.Cplusplus, false) diff --git a/chore/_xtool/llcppsymg/parse/parse.go b/chore/_xtool/llcppsymg/parse/parse.go index 34f65fce8..6ebd62fe6 100644 --- a/chore/_xtool/llcppsymg/parse/parse.go +++ b/chore/_xtool/llcppsymg/parse/parse.go @@ -2,9 +2,6 @@ package parse import ( "errors" - "fmt" - "os" - "path/filepath" "strconv" "strings" @@ -189,37 +186,3 @@ func ParseHeaderFile(files []string, Prefixes []string, isCpp bool, isTemp bool) index.Dispose() return processer.SymbolMap, nil } - -func GenHeaderFilePath(cflags string, files []string) ([]string, error) { - prefixPath := strings.TrimPrefix(cflags, "-I") - - var validPaths []string - var errs []string - - for _, file := range files { - if file == "" { - continue - } - fullPath := filepath.Join(prefixPath, file) - if f, err := os.Open(fullPath); err != nil { - if os.IsNotExist(err) { - errs = append(errs, fmt.Sprintf("file not found: %s", file)) - } else { - errs = append(errs, fmt.Sprintf("error accessing file %s: %v", file, err)) - } - } else { - f.Close() - validPaths = append(validPaths, fullPath) - } - } - - if len(validPaths) == 0 && len(errs) == 0 { - return nil, fmt.Errorf("no valid header files") - } - - if len(errs) > 0 { - return validPaths, fmt.Errorf("some files not found or inaccessible: %v", errs) - } - - return validPaths, nil -} diff --git a/chore/_xtool/llcppsymg/symbol/symbol.go b/chore/_xtool/llcppsymg/symbol/symbol.go index 0a49936b6..ba556a6d9 100644 --- a/chore/_xtool/llcppsymg/symbol/symbol.go +++ b/chore/_xtool/llcppsymg/symbol/symbol.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "os" - "path/filepath" "runtime" "strings" "unsafe" @@ -12,6 +11,7 @@ import ( "github.com/goplus/llgo/c" "github.com/goplus/llgo/c/cjson" "github.com/goplus/llgo/chore/_xtool/llcppsymg/config" + "github.com/goplus/llgo/chore/_xtool/llcppsymg/config/cfgparse" "github.com/goplus/llgo/chore/_xtool/llcppsymg/parse" "github.com/goplus/llgo/chore/llcppg/types" "github.com/goplus/llgo/xtool/nm" @@ -20,73 +20,18 @@ import ( type dbgFlags = int const ( - DbgConf dbgFlags = 1 << iota - DbgSymbol - - DbgFlagAll = DbgConf | DbgSymbol + DbgSymbol dbgFlags = 1 << iota + DbgFlagAll = DbgSymbol ) var ( - debugConf bool debugSymbol bool ) func SetDebug(dbgFlags dbgFlags) { - debugConf = (dbgFlags & DbgConf) != 0 debugSymbol = (dbgFlags & DbgSymbol) != 0 } -type LibConfig struct { - Paths []string - Names []string -} - -func ParseLibConfig(lib string) *LibConfig { - parts := strings.Fields(lib) - config := &LibConfig{} - - for _, part := range parts { - if strings.HasPrefix(part, "-L") { - config.Paths = append(config.Paths, part[2:]) - } else if strings.HasPrefix(part, "-l") { - config.Names = append(config.Names, part[2:]) - } - } - - return config -} - -func GenDylibPaths(config *LibConfig, defaultPaths []string) ([]string, error) { - var foundPaths []string - var notFound []string - affix := ".dylib" - if runtime.GOOS == "linux" { - affix = ".so" - } - searchPaths := append(config.Paths, defaultPaths...) - for _, name := range config.Names { - var foundPath string - for _, path := range searchPaths { - dylibPath := filepath.Join(path, "lib"+name+affix) - if _, err := os.Stat(dylibPath); err == nil { - foundPath = dylibPath - } - } - if foundPath != "" { - foundPaths = append(foundPaths, foundPath) - } else { - notFound = append(notFound, name) - } - } - if len(notFound) > 0 && debugSymbol { - fmt.Printf("Warning: Some libraries were not found: %s\n", strings.Join(notFound, ", ")) - } - if len(foundPaths) == 0 { - return nil, fmt.Errorf("failed to find any libraries") - } - return foundPaths, nil -} - // ParseDylibSymbols parses symbols from dynamic libraries specified in the lib string. // It handles multiple libraries (e.g., -L/opt/homebrew/lib -llua -lm) and returns // symbols if at least one library is successfully parsed. Errors from inaccessible @@ -94,23 +39,28 @@ func GenDylibPaths(config *LibConfig, defaultPaths []string) ([]string, error) { // // Returns symbols and nil error if any symbols are found, or nil and error if none found. func ParseDylibSymbols(lib string) ([]*nm.Symbol, error) { - if debugConf { + if debugSymbol { fmt.Println("ParseDylibSymbols:from", lib) } - conf := ParseLibConfig(lib) - if debugConf { + sysPaths := getSysLibPaths() + lbs := cfgparse.ParseLibs(lib) + if debugSymbol { fmt.Println("ParseDylibSymbols:LibConfig Parse To") - fmt.Println("conf.Names: ", conf.Names) - fmt.Println("conf.Paths: ", conf.Paths) + fmt.Println("libs.Names: ", lbs.Names) + fmt.Println("libs.Paths: ", lbs.Paths) } - defaultPaths := getSysLibPaths() - dylibPaths, err := GenDylibPaths(conf, defaultPaths) + dylibPaths, notFounds, err := lbs.GenDylibPaths(sysPaths) if err != nil { return nil, fmt.Errorf("failed to generate some dylib paths: %v", err) } if debugSymbol { fmt.Println("ParseDylibSymbols:dylibPaths", dylibPaths) + if len(notFounds) > 0 { + fmt.Println("ParseDylibSymbols:not found libname", notFounds) + } else { + fmt.Println("ParseDylibSymbols:every library is found") + } } var symbols []*nm.Symbol @@ -151,7 +101,7 @@ func ParseDylibSymbols(lib string) ([]*nm.Symbol, error) { func getSysLibPaths() []string { var paths []string if runtime.GOOS == "linux" { - if debugConf { + if debugSymbol { fmt.Println("getSysLibPaths:find sys lib path from linux") } paths = []string{ @@ -159,13 +109,13 @@ func getSysLibPaths() []string { "/usr/local/lib", } paths = append(paths, getPath("/etc/ld.so.conf")...) - if debugConf && len(paths) == 0 { + if debugSymbol && len(paths) == 0 { fmt.Println("getSysLibPaths:/etc/ld.so.conf havent find any path") } confd := "/etc/ld.so.conf.d" dir, err := os.Stat(confd) if err != nil || !dir.IsDir() { - if debugConf { + if debugSymbol { fmt.Println("getSysLibPaths:/etc/ld.so.conf.d not found or not dir") } return paths @@ -183,7 +133,7 @@ func getSysLibPaths() []string { } func getPath(file string) []string { - if debugConf { + if debugSymbol { fmt.Println("getPath:from", file) } var paths []string