diff --git a/tests/modules/private/select_script/test.lua b/tests/modules/private/select_script/test.lua new file mode 100644 index 00000000000..ab37d732e73 --- /dev/null +++ b/tests/modules/private/select_script/test.lua @@ -0,0 +1,111 @@ +import("private.core.base.select_script") + +function _match_pattern(pattern, opt) + pattern = pattern:gsub("([%+%.%-%^%$%(%)%%])", "%%%1") + pattern = pattern:gsub("%*", "\001") + pattern = pattern:gsub("\001", ".*") + return select_script({[pattern] = true}, opt) == true +end + +function test_plat_only(t) + t:require(_match_pattern("*", {plat = "macosx"})) + t:require(_match_pattern("macosx", {plat = "macosx"})) + t:require(_match_pattern("macosx,linux", {plat = "macosx"})) + t:require(_match_pattern("mac*", {plat = "macosx"})) + t:require_not(_match_pattern("macosx", {plat = "linux"})) + t:require_not(_match_pattern("linux", {plat = "macosx"})) + t:require_not(_match_pattern("!macosx", {plat = "macosx"})) + t:require_not(_match_pattern("!mac*", {plat = "macosx"})) + t:require(_match_pattern("!macosx", {plat = "linux"})) + t:require(_match_pattern("!mac*", {plat = "linux"})) +end + +function test_plat_arch(t) + t:require(_match_pattern("*|x86_64", {plat = "macosx", arch = "x86_64"})) + t:require(_match_pattern("macosx|x86_64", {plat = "macosx", arch = "x86_64"})) + t:require(_match_pattern("macosx|x86_64,linux|x86_64", {plat = "macosx", arch = "x86_64"})) + t:require(_match_pattern("macosx|x86_*", {plat = "macosx", arch = "x86_64"})) + t:require_not(_match_pattern("macosx|x86_64", {plat = "linux", arch = "x86_64"})) + t:require_not(_match_pattern("macosx|i386", {plat = "macosx", arch = "x86_64"})) + t:require_not(_match_pattern("!macosx|x86_64", {plat = "macosx", arch = "x86_64"})) + t:require_not(_match_pattern("!mac*|x86_64", {plat = "macosx", arch = "x86_64"})) + t:require(_match_pattern("!macosx|x86_64", {plat = "linux", arch = "x86_64"})) + t:require(_match_pattern("!mac*|x86_64", {plat = "linux", arch = "x86_64"})) + t:require(_match_pattern("macosx|!i386", {plat = "macosx", arch = "x86_64"})) + t:require(_match_pattern("!macosx|!i386", {plat = "linux", arch = "x86_64"})) + t:require(_match_pattern("windows|!x86", {plat = "windows", arch = "x64"})) + t:require_not(_match_pattern("windows|!x86", {plat = "android", arch = "arm64-v8a"})) + t:require(_match_pattern("macosx|native", {plat = "macosx", arch = "x86_64", subarch = "x86_64"})) + t:require(_match_pattern("macosx|!native", {plat = "macosx", arch = "arm64", subarch = "x86_64"})) + t:require_not(_match_pattern("macosx|!native", {plat = "macosx", arch = "x86_64", subarch = "x86_64"})) + t:require_not(_match_pattern("windows|native", {plat = "macosx", arch = "x86_64", subarch = "x86_64"})) +end + +function test_subhost_only(t) + t:require(_match_pattern("@*", {subhost = "macosx"})) + t:require(_match_pattern("@macosx", {subhost = "macosx"})) + t:require(_match_pattern("@macosx,@linux", {subhost = "macosx"})) + t:require(_match_pattern("@mac*", {subhost = "macosx"})) + t:require_not(_match_pattern("@macosx", {subhost = "linux"})) + t:require_not(_match_pattern("@linux", {subhost = "macosx"})) + t:require_not(_match_pattern("@!macosx", {subhost = "macosx"})) + t:require_not(_match_pattern("@!mac*", {subhost = "macosx"})) + t:require(_match_pattern("@!macosx", {subhost = "linux"})) + t:require(_match_pattern("@!mac*", {subhost = "linux"})) +end + +function test_subhost_subarch(t) + t:require(_match_pattern("@*|x86_64", {subhost = "macosx", subarch = "x86_64"})) + t:require(_match_pattern("@macosx|x86_64", {subhost = "macosx", subarch = "x86_64"})) + t:require(_match_pattern("@macosx|x86_64,@linux|x86_64", {subhost = "macosx", subarch = "x86_64"})) + t:require(_match_pattern("@macosx|x86_*", {subhost = "macosx", subarch = "x86_64"})) + t:require_not(_match_pattern("@macosx|x86_64", {subhost = "linux", subarch = "x86_64"})) + t:require_not(_match_pattern("@macosx|i386", {subhost = "macosx", subarch = "x86_64"})) + t:require_not(_match_pattern("@!macosx|x86_64", {subhost = "macosx", subarch = "x86_64"})) + t:require_not(_match_pattern("@!mac*|x86_64", {subhost = "macosx", subarch = "x86_64"})) + t:require(_match_pattern("@!macosx|x86_64", {subhost = "linux", subarch = "x86_64"})) + t:require(_match_pattern("@!mac*|x86_64", {subhost = "linux", subarch = "x86_64"})) + t:require(_match_pattern("@macosx|!i386", {subhost = "macosx", subarch = "x86_64"})) + t:require(_match_pattern("@!macosx|!i386", {subhost = "linux", subarch = "x86_64"})) + t:require(_match_pattern("@windows|!x86", {subhost = "windows", subarch = "x64"})) + t:require_not(_match_pattern("@windows|!x86", {subhost = "android", subarch = "arm64-v8a"})) + t:require(_match_pattern("@macosx|native", {subhost = "macosx", subarch = "x86_64"})) + t:require(_match_pattern("@macosx|native", {subhost = "macosx", subarch = "arm64"})) + t:require_not(_match_pattern("@macosx|!native", {subhost = "macosx", subarch = "x86_64"})) + t:require_not(_match_pattern("@windows|native", {subhost = "macosx", subarch = "x86_64"})) +end + +function test_plat_subhost(t) + t:require(_match_pattern("*@macosx", {plat = "macosx", subhost = "macosx"})) + t:require(_match_pattern("android@macosx", {plat = "android", subhost = "macosx"})) + t:require(_match_pattern("android@macosx,linux", {plat = "android", subhost = "linux"})) + t:require(_match_pattern("android@mac*", {plat = "android", subhost = "macosx"})) + t:require(_match_pattern("android@!macosx", {plat = "android", subhost = "linux"})) + t:require_not(_match_pattern("!android@macosx", {plat = "android", subhost = "macosx"})) + t:require(_match_pattern("!iphon*@macosx", {plat = "linux", subhost = "macosx"})) +end + +function test_plat_arch_subhost(t) + t:require(_match_pattern("*|x86_64@macosx", {plat = "macosx", subhost = "macosx", arch = "x86_64"})) + t:require(_match_pattern("android|arm64-v8a@macosx", {plat = "android", subhost = "macosx", arch = "arm64-v8a"})) + t:require(_match_pattern("android|x86_64@macosx,linux", {plat = "android", subhost = "linux", arch = "x86_64"})) + t:require(_match_pattern("android|x86_64@mac*", {plat = "android", subhost = "macosx", arch = "x86_64"})) + t:require(_match_pattern("android|x86_64@!macosx", {plat = "android", subhost = "linux", arch = "x86_64"})) + t:require_not(_match_pattern("!android|x86_64@macosx", {plat = "android", subhost = "macosx", arch = "x86_64"})) + t:require(_match_pattern("!iphon*|x86_64@macosx", {plat = "linux", subhost = "macosx", arch = "x86_64"})) + t:require(_match_pattern("iphon*|arm64@macosx", {plat = "iphoneos", subhost = "macosx", arch = "arm64"})) + t:require_not(_match_pattern("iphon*|arm64@macosx", {plat = "iphoneos", subhost = "linux", arch = "arm64"})) +end + +function test_plat_arch_subhost_subarch(t) + t:require(_match_pattern("*|x86_64@macosx|x86_64", {plat = "macosx", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) + t:require(_match_pattern("android|arm64-v8a@macosx|x86_64", {plat = "android", subhost = "macosx", arch = "arm64-v8a", subarch = "x86_64"})) + t:require(_match_pattern("android|x86_64@macosx|x86_64,linux|x86_64", {plat = "android", subhost = "linux", arch = "x86_64", subarch = "x86_64"})) + t:require(_match_pattern("android|x86_64@mac*|x86_64", {plat = "android", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) + t:require(_match_pattern("android|x86_64@!macosx|x86_64", {plat = "android", subhost = "linux", arch = "x86_64", subarch = "x86_64"})) + t:require_not(_match_pattern("!android|x86_64@macosx|x86_64", {plat = "android", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) + t:require(_match_pattern("!iphon*|x86_64@macosx|x86_64", {plat = "linux", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) + t:require(_match_pattern("iphon*|arm64@macosx|x86_64", {plat = "iphoneos", subhost = "macosx", arch = "arm64", subarch = "x86_64"})) + t:require_not(_match_pattern("iphon*|arm64@macosx|x86_64", {plat = "iphoneos", subhost = "linux", arch = "arm64", subarch = "x86_64"})) + t:require(_match_pattern("android|native@macosx|x86_64", {plat = "android", subhost = "macosx", arch = "x86_64", subarch = "x86_64"})) +end diff --git a/xmake/core/base/private/select_script.lua b/xmake/core/base/private/select_script.lua index 1fe8a77fd72..3fe88163f6e 100644 --- a/xmake/core/base/private/select_script.lua +++ b/xmake/core/base/private/select_script.lua @@ -23,32 +23,53 @@ local table = require("base/table") local utils = require("base/utils") -- match pattern, matched mode: plat|arch, excluded mode: !plat|arch -function _match_pattern(pattern, plat, arch, excluded) - -- support native arch, e.g. macosx|native - -- @see https://github.com/xmake-io/xmake/issues/4657 - if pattern:find("native", 1, true) then - local splitinfo = pattern:split("|") - local pattern_plat = splitinfo[1] - local pattern_arch = splitinfo[2] - if pattern_arch and pattern_plat:trim("!") == os.subhost() then - pattern_arch = pattern_arch:gsub("native", os.subarch()) - pattern = pattern_plat .. "|" .. pattern_arch +function _match_pattern(pattern, plat, arch, opt) + opt = opt or {} + local excluded = opt.excluded + local subhost = opt.subhost or os.subhost() + local subarch = opt.subarch or os.subarch() + local splitinfo = pattern:split("|", {strict = true, plain = true}) + local pattern_plat = splitinfo[1] + local pattern_arch = splitinfo[2] + if pattern_plat and #pattern_plat > 0 then + local matched = false + local is_excluded_pattern = pattern_plat:find('!', 1, true) + if excluded and is_excluded_pattern then + matched = not ('!' .. plat):match('^' .. pattern_plat .. '$') + elseif not is_excluded_pattern then + matched = plat:match('^' .. pattern_plat .. '$') + end + if not matched then + return false + end + end + if pattern_arch and #pattern_arch > 0 then + -- support native arch, e.g. macosx|native + -- @see https://github.com/xmake-io/xmake/issues/4657 + pattern_arch = pattern_arch:gsub("native", subarch) + + local matched = false + local is_excluded_pattern = pattern_arch:find('!', 1, true) + if excluded and is_excluded_pattern then + matched = not ('!' .. arch):match('^' .. pattern_arch .. '$') + elseif not is_excluded_pattern then + matched = arch:match('^' .. pattern_arch .. '$') + end + if not matched then + return false end end - local is_excluded_pattern = pattern:find('!', 1, true) - if excluded and is_excluded_pattern then - return not ('!' .. plat .. '|' .. arch):match('^' .. pattern .. '$') and - not (plat .. '|!' .. arch):match('^' .. pattern .. '$') and - not ('!' .. plat):match('^' .. pattern .. '$') - elseif not is_excluded_pattern then - return (plat .. '|' .. arch):match('^' .. pattern .. '$') or plat:match('^' .. pattern .. '$') + if not pattern_plat and not pattern_arch then + os.raise("invalid script pattern: %s", pattern) end + return true end + -- match patterns -function _match_patterns(patterns, plat, arch, excluded) +function _match_patterns(patterns, plat, arch, opt) for _, pattern in ipairs(patterns) do - if _match_pattern(pattern, plat, arch, excluded) then + if _match_pattern(pattern, plat, arch, opt) then return true end end @@ -86,7 +107,8 @@ end -- `!android|armeabi-v7a@!linux|!x86_64` -- `!linux|*` -- -function _match_script(pattern, plat, arch, excluded) +function _match_script(pattern, opt) + opt = opt or {} local splitinfo = pattern:split("@", {strict = true, plain = true}) local plat_part = splitinfo[1] local host_part = splitinfo[2] @@ -98,17 +120,21 @@ function _match_script(pattern, plat, arch, excluded) if host_part and #host_part > 0 then host_patterns = host_part:split(",", {plain = true}) end + local plat = opt.plat or "" + local arch = opt.arch or "" + local subhost = opt.subhost or os.subhost() + local subarch = opt.subarch or os.subarch() if plat_patterns and #plat_patterns > 0 then - if _match_patterns(plat_patterns, plat, arch, excluded) then + if _match_patterns(plat_patterns, plat, arch, opt) then if host_patterns and #host_patterns > 0 and - not _match_patterns(host_patterns, os.subhost(), os.subarch(), excluded) then + not _match_patterns(host_patterns, subhost, subarch, opt) then return false end return true end else if host_patterns and #host_patterns > 0 then - return _match_patterns(host_patterns, os.subhost(), os.subarch(), excluded) + return _match_patterns(host_patterns, subhost, subarch, opt) end end end @@ -120,11 +146,9 @@ function select_script(scripts, opt) if type(scripts) == "function" then result = scripts elseif type(scripts) == "table" then - local plat = opt.plat or "" - local arch = opt.arch or "" local script_matched for pattern, script in pairs(scripts) do - if not pattern:startswith("__") and _match_script(pattern, plat, arch) then + if not pattern:startswith("__") and _match_script(pattern, opt) then script_matched = script break end @@ -132,8 +156,9 @@ function select_script(scripts, opt) if not script_matched then local scripts_fallback = {} local patterns_fallback = {} + local excluded_opt = table.join(opt, {excluded = true}) for pattern, script in pairs(scripts) do - if not pattern:startswith("__") and _match_script(pattern, plat, arch, true) then + if not pattern:startswith("__") and _match_script(pattern, excluded_opt) then table.insert(scripts_fallback, script) table.insert(patterns_fallback, pattern) end