llcppsymg:multiple dylib path search
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user