summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKochabStar <[email protected]>2026-01-14 14:31:21 +0800
committerKochabStar <[email protected]>2026-01-14 14:31:21 +0800
commitffdbcf451672640116d5112701f8fd41fcca27fc (patch)
tree257b59391e630898b27a85eb13e263d42a530242
parentcc4413cbac8b55ad099c0463c96a45e9b1703dc3 (diff)
fix(nuget): improve library file matching with score-based selection
- add path component matching to avoid x86/x86_64 confusion - implement score-based lib file selection for better architecture matching - support multiple include directory patterns - deduplicate includedirs and linkdirs in result
-rw-r--r--xmake/modules/package/manager/nuget/find_package.lua142
1 files changed, 102 insertions, 40 deletions
diff --git a/xmake/modules/package/manager/nuget/find_package.lua b/xmake/modules/package/manager/nuget/find_package.lua
index 2772255b9..a206eb301 100644
--- a/xmake/modules/package/manager/nuget/find_package.lua
+++ b/xmake/modules/package/manager/nuget/find_package.lua
@@ -28,37 +28,71 @@ import("core.project.config")
import("core.project.target")
import("private.utils.toolchain", {alias = "toolchain_utils"})
+-- check if pattern matches as a complete path component
+-- e.g. "x86" should match "/x86/" but not "/x86_64/"
+function _match_path_component(file_lower, pattern)
+ local s, e = file_lower:find(pattern, 1, true)
+ while s do
+ -- check boundary: start of string or path separator before
+ local before_ok = (s == 1) or file_lower:sub(s - 1, s - 1):match("[/\\]")
+ -- check boundary: end of string or path separator after
+ local after_ok = (e == #file_lower) or file_lower:sub(e + 1, e + 1):match("[/\\]")
+ if before_ok and after_ok then
+ return true
+ end
+ -- continue searching from next position
+ s, e = file_lower:find(pattern, e + 1, true)
+ end
+ return false
+end
+
+-- match library file by analyzing path components
+-- returns match score (higher is better), 0 means no match
+function _match_libfile(file, libarch, toolset, libmode, runtime)
+ -- architecture aliases for matching
+ local arch_patterns = {
+ x64 = {"x64", "amd64", "x86_64"},
+ Win32 = {"win32", "x86", "i386", "i686"},
+ arm64 = {"arm64", "aarch64"},
+ }
+ local target_archs = arch_patterns[libarch] or {libarch:lower()}
+
+ -- check if file path contains target architecture
+ local file_lower = file:lower()
+ local has_arch = false
+ for _, arch_name in ipairs(target_archs) do
+ if _match_path_component(file_lower, arch_name) then
+ has_arch = true
+ break
+ end
+ end
+
+ -- check if file contains other architecture (should exclude)
+ for arch, patterns in pairs(arch_patterns) do
+ if arch ~= libarch then
+ for _, p in ipairs(patterns) do
+ if _match_path_component(file_lower, p) then
+ return 0 -- contains wrong architecture
+ end
+ end
+ end
+ end
+
+ -- calculate match score based on path components
+ local score = has_arch and 10 or 1
+ if toolset and file_lower:find(toolset:lower(), 1, true) then
+ score = score + 4
+ end
+ if file_lower:find(libmode:lower(), 1, true) then
+ score = score + 2
+ end
+ if file_lower:find(runtime:lower(), 1, true) then
+ score = score + 1
+ end
+ return score
+end
+
-- find native package files
--- e.g.
---[[
- "build/native/include/crc32.h",
- "build/native/include/deflate.h",
- "build/native/include/gzguts.h",
- "build/native/include/inffast.h",
- "build/native/include/inffixed.h",
- "build/native/include/inflate.h",
- "build/native/include/inftrees.h",
- "build/native/include/trees.h",
- "build/native/include/zconf.h",
- "build/native/include/zlib.h",
- "build/native/include/zutil.h",
- "build/native/lib/Win32/v140/Debug/zlib.lib",
- "build/native/lib/Win32/v140/Release/zlib.lib",
- "build/native/lib/Win32/v141/Debug/zlib.lib",
- "build/native/lib/Win32/v141/Release/zlib.lib",
- "build/native/lib/Win32/v142/Debug/MultiThreadedDebug/zlib.lib",
- "build/native/lib/Win32/v142/Debug/MultiThreadedDebugDLL/zlib.lib",
- "build/native/lib/Win32/v142/Release/MultiThreaded/zlib.lib",
- "build/native/lib/Win32/v142/Release/MultiThreadedDLL/zlib.lib",
- "build/native/lib/x64/v140/Debug/zlib.lib",
- "build/native/lib/x64/v140/Release/zlib.lib",
- "build/native/lib/x64/v141/Debug/zlib.lib",
- "build/native/lib/x64/v141/Release/zlib.lib",
- "build/native/lib/x64/v142/Debug/MultiThreadedDebug/zlib.lib",
- "build/native/lib/x64/v142/Debug/MultiThreadedDebugDLL/zlib.lib",
- "build/native/lib/x64/v142/Release/MultiThreaded/zlib.lib",
- "build/native/lib/x64/v142/Release/MultiThreadedDLL/zlib.lib",
-]]
function _find_package(name, result, opt)
local arch = opt.arch
local plat = opt.plat
@@ -72,7 +106,6 @@ function _find_package(name, result, opt)
MD = "MultiThreadedDLL",
MDd = "MultiThreadedDebugDLL"}
local installdir = path.join(opt.packagesdir, name)
- local libdir = "build/native/lib"
local runtime = assert(runtimes[configs.runtimes], "unknown runtimes %s", configs.runtimes)
local toolset = toolchain_utils.get_vs_toolset_ver(toolchain.load("msvc", {plat = plat, arch = arch}):config("vs_toolset") or config.get("vs_toolset"))
local libarch = libarchs[arch] or "x64"
@@ -82,24 +115,44 @@ function _find_package(name, result, opt)
file = file:trim()
-- get includedirs
- if file:find("/include/", 1, true) or file:startswith("include/") then
- result.includedirs = result.includedirs or {}
- table.insert(result.includedirs, path.join(installdir, "include"))
+ -- support multiple include directory patterns:
+ -- e.g. build/native/include/*.h, build/native/include-winrt/*.h
+ if file:endswith(".h") or file:endswith(".hpp") or file:endswith(".hxx") then
+ local dir = path.directory(file)
+ if dir and (dir:find("include", 1, true) or dir:find("inc", 1, true)) then
+ result.includedirs = result.includedirs or {}
+ table.insert(result.includedirs, path.join(installdir, dir))
+ end
end
-- get linkdirs and links
+ -- use score-based matching to support various directory structures
if file:endswith(".lib") then
- local searchdirs = {}
- table.insert(searchdirs, path.unix(path.join(libdir, libarch, toolset, libmode, runtime)))
- table.insert(searchdirs, path.unix(path.join(libdir, libarch)))
- for _, searchdir in ipairs(searchdirs) do
- if file:startswith(searchdir .. "/") then
+ local score = _match_libfile(file, libarch, toolset, libmode, runtime)
+ if score > 0 then
+ local libname = path.filename(filepath)
+ -- check if we already have this lib with a better match
+ result._libscores = result._libscores or {}
+ local existing_score = result._libscores[libname] or 0
+ if score > existing_score then
+ -- remove old entry if exists
+ if existing_score > 0 then
+ for i, v in ipairs(result.links or {}) do
+ if target.linkname(libname, {plat = plat}) == v then
+ table.remove(result.links, i)
+ table.remove(result.linkdirs, i)
+ table.remove(result.libfiles, i)
+ break
+ end
+ end
+ end
result.links = result.links or {}
result.linkdirs = result.linkdirs or {}
result.libfiles = result.libfiles or {}
table.insert(result.linkdirs, path.directory(filepath))
- table.insert(result.links, target.linkname(path.filename(filepath), {plat = plat}))
+ table.insert(result.links, target.linkname(libname, {plat = plat}))
table.insert(result.libfiles, filepath)
+ result._libscores[libname] = score
end
end
end
@@ -159,7 +212,16 @@ function main(name, opt)
if target_root and metainfo.targets and metainfo.libraries and metainfo.packagesdir then
local result = {}
_find_package(target_root, result, metainfo)
+ -- clean up internal scoring data
+ result._libscores = nil
if result.links or result.includedirs then
+ -- deduplicate paths
+ if result.includedirs then
+ result.includedirs = table.unique(result.includedirs)
+ end
+ if result.linkdirs then
+ result.linkdirs = table.unique(result.linkdirs)
+ end
return result
end
end