wails/v3/internal/libpath/libpath_other.go
Lea Anthony f1a4ffe72d
feat(linux): add libpath package for finding native library paths (#4847)
* feat(linux): add libpath package for finding native library paths

Add a new internal/libpath package that locates shared libraries (.so files)
on Linux systems. Supports multiple distributions and package managers.

Features:
- Multi-tier search: pkg-config -> ldconfig -> filesystem scanning
- Parallel search using goroutines for faster lookups
- Cached dynamic path discovery for Flatpak, Snap, and Nix
- Support for Debian/Ubuntu, Fedora/RHEL, Arch, openSUSE, NixOS
- Context-aware cancellation for graceful shutdown

Performance:
- Library found: ~1.4ms (parallel search)
- Library not found: ~46ms (was 84ms sequential)
- Cached path discovery: 14ns (was 15ms uncached)

* feat(libpath): add multi-library parallel search functions

Add functions to search for multiple library candidates in parallel:

- FindFirstLibrary: Search multiple libs in parallel, return first found
- FindFirstLibraryOrdered: Search in order of preference (for version priority)
- FindAllLibraries: Find all available libraries from a list

Useful when the exact library version is unknown, e.g.:
  match, _ := FindFirstLibrary("webkit2gtk-4.1", "webkit2gtk-4.0", "webkit2gtk-6.0")

Also adds findLibraryPathCtx for context-aware searching used by the
multi-library functions.

* refactor(libpath): split into separate files and fix race condition

Split libpath_linux.go into smaller, focused files:
- cache_linux.go: Path cache with thread-safe init/invalidate
- flatpak_linux.go: Flatpak runtime path discovery
- snap_linux.go: Snap package path discovery
- nix_linux.go: Nix/NixOS path discovery
- libpath_linux.go: Core search functions

Fixes:
- Fix data race between init() and invalidate() by holding mutex
  during cache writes inside sync.Once.Do (CodeRabbit review)
- Fix FindLibraryPathWithOptions not searching dynamic paths
  (Flatpak/Snap/Nix) - now uses GetAllLibPaths() (CodeRabbit review)
2026-01-04 11:59:22 +11:00

73 lines
2 KiB
Go

//go:build !linux
package libpath
// FindLibraryPath is a stub for non-Linux platforms.
func FindLibraryPath(libName string) (string, error) {
return "", &LibraryNotFoundError{Name: libName}
}
// FindLibraryFile is a stub for non-Linux platforms.
func FindLibraryFile(fileName string) (string, error) {
return "", &LibraryNotFoundError{Name: fileName}
}
// GetAllLibPaths returns an empty slice on non-Linux platforms.
func GetAllLibPaths() []string {
return nil
}
// InvalidateCache is a no-op on non-Linux platforms.
func InvalidateCache() {}
// FindOptions controls library search behavior.
type FindOptions struct {
IncludeCurrentDir bool
ExtraPaths []string
}
// FindLibraryPathWithOptions is a stub for non-Linux platforms.
func FindLibraryPathWithOptions(libName string, opts FindOptions) (string, error) {
return "", &LibraryNotFoundError{Name: libName}
}
// LibraryNotFoundError is returned when a library cannot be found.
type LibraryNotFoundError struct {
Name string
}
func (e *LibraryNotFoundError) Error() string {
return "library not found: " + e.Name
}
// LibraryMatch holds information about a found library.
type LibraryMatch struct {
Name string
Path string
}
// FindFirstLibrary is a stub for non-Linux platforms.
func FindFirstLibrary(libNames ...string) (*LibraryMatch, error) {
if len(libNames) == 0 {
return nil, &LibraryNotFoundError{Name: "no libraries specified"}
}
return nil, &LibraryNotFoundError{Name: libNames[0]}
}
// FindFirstLibraryOrdered is a stub for non-Linux platforms.
func FindFirstLibraryOrdered(libNames ...string) (*LibraryMatch, error) {
if len(libNames) == 0 {
return nil, &LibraryNotFoundError{Name: "no libraries specified"}
}
return nil, &LibraryNotFoundError{Name: libNames[0]}
}
// FindAllLibraries is a stub for non-Linux platforms.
func FindAllLibraries(libNames ...string) []LibraryMatch {
return nil
}
// FindLibraryPathSequential is a stub for non-Linux platforms.
func FindLibraryPathSequential(libName string) (string, error) {
return "", &LibraryNotFoundError{Name: libName}
}