llcppsymg:multiple dylib path search

This commit is contained in:
luoliwoshang
2024-10-15 23:08:20 +08:00
parent 7bd3b29a11
commit d5237d1a07
3 changed files with 187 additions and 31 deletions

View File

@@ -1,21 +1,36 @@
#stdout #stdout
=== Test GenDylibPaths === === Test ParseLibConfig ===
Test case: Lua library Test case: Lua library
Input: -L/opt/homebrew/lib -llua -lm Input: -L/opt/homebrew/lib -llua -lm
Output: [/opt/homebrew/lib/liblua.dylib /opt/homebrew/lib/libm.dylib] Paths: [/opt/homebrew/lib]
Names: [lua m]
Test case: SQLite library Test case: SQLite library
Input: -L/opt/homebrew/opt/sqlite/lib -lsqlite3 Input: -L/opt/homebrew/opt/sqlite/lib -lsqlite3
Output: [/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib] Paths: [/opt/homebrew/opt/sqlite/lib]
Names: [sqlite3]
Test case: INIReader library Test case: INIReader library
Input: -L/opt/homebrew/Cellar/inih/58/lib -lINIReader Input: -L/opt/homebrew/Cellar/inih/58/lib -lINIReader
Output: [/opt/homebrew/Cellar/inih/58/lib/libINIReader.dylib] 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 Test case: No valid library
Input: -L/opt/homebrew/lib Input: -L/opt/homebrew/lib
Error: failed to parse pkg-config output: -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
Warning: Some libraries were not found: notexist
=== Test GetCommonSymbols === === Test GetCommonSymbols ===
Test Case: Lua symbols Test Case: Lua symbols

View File

@@ -3,7 +3,10 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath"
"runtime"
"sort" "sort"
"strings"
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse" "github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
"github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol" "github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol"
@@ -12,13 +15,14 @@ import (
) )
func main() { func main() {
TestParseLibConfig()
TestGenDylibPaths() TestGenDylibPaths()
TestGetCommonSymbols() TestGetCommonSymbols()
TestReadExistingSymbolTable() TestReadExistingSymbolTable()
TestGenSymbolTableData() TestGenSymbolTableData()
} }
func TestGenDylibPaths() { func TestParseLibConfig() {
fmt.Println("=== Test GenDylibPaths ===") fmt.Println("=== Test ParseLibConfig ===")
testCases := []struct { testCases := []struct {
name string name string
@@ -36,6 +40,10 @@ func TestGenDylibPaths() {
name: "INIReader library", name: "INIReader library",
input: "-L/opt/homebrew/Cellar/inih/58/lib -lINIReader", 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", name: "No valid library",
input: "-L/opt/homebrew/lib", input: "-L/opt/homebrew/lib",
@@ -46,16 +54,119 @@ func TestGenDylibPaths() {
fmt.Printf("Test case: %s\n", tc.name) fmt.Printf("Test case: %s\n", tc.name)
fmt.Printf("Input: %s\n", tc.input) fmt.Printf("Input: %s\n", tc.input)
result, err := symbol.GenDylibPaths(tc.input) conf := symbol.ParseLibConfig(tc.input)
if err != nil { fmt.Println("Paths:", conf.Paths)
fmt.Printf("Error: %v\n", err) fmt.Println("Names:", conf.Names)
} else {
fmt.Printf("Output: %v\n", result)
}
fmt.Println()
} }
} }
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() { func TestGetCommonSymbols() {
fmt.Println("=== Test GetCommonSymbols ===") fmt.Println("=== Test GetCommonSymbols ===")
testCases := []struct { testCases := []struct {

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"unsafe" "unsafe"
@@ -16,27 +17,55 @@ import (
"github.com/goplus/llgo/xtool/nm" "github.com/goplus/llgo/xtool/nm"
) )
func GenDylibPaths(lib string) ([]string, error) { type LibConfig struct {
Paths []string
Names []string
}
func ParseLibConfig(lib string) *LibConfig {
parts := strings.Fields(lib) parts := strings.Fields(lib)
var libPath, libName string config := &LibConfig{}
var dylibPaths []string
for _, part := range parts { for _, part := range parts {
if strings.HasPrefix(part, "-L") { if strings.HasPrefix(part, "-L") {
libPath = part[2:] config.Paths = append(config.Paths, part[2:])
} else if strings.HasPrefix(part, "-l") { } else if strings.HasPrefix(part, "-l") {
libName = part[2:] config.Names = append(config.Names, part[2:])
if libPath != "" && libName != "" {
dylibPaths = append(dylibPaths, filepath.Join(libPath, "lib"+libName+".dylib"))
}
} }
} }
if len(dylibPaths) == 0 { return config
return nil, fmt.Errorf("failed to parse pkg-config output: %s", lib) }
}
return dylibPaths, nil 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 {
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. // ParseDylibSymbols parses symbols from dynamic libraries specified in the lib string.
@@ -48,7 +77,8 @@ func GenDylibPaths(lib string) ([]string, error) {
func ParseDylibSymbols(lib string) ([]*nm.Symbol, error) { func ParseDylibSymbols(lib string) ([]*nm.Symbol, error) {
fmt.Printf("parse dylib symbols from config lib:%s\n", lib) fmt.Printf("parse dylib symbols from config lib:%s\n", lib)
dylibPaths, err := GenDylibPaths(lib) conf := ParseLibConfig(lib)
dylibPaths, err := GenDylibPaths(conf, []string{})
if err != nil { if err != nil {
fmt.Printf("Warning: failed to generate some dylib paths: %v\n", err) fmt.Printf("Warning: failed to generate some dylib paths: %v\n", err)
} }