--!A cross-platform build utility based on Lua -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- -- Copyright (C) 2015-present, TBOOX Open Source Group. -- -- @author ruki -- @file select_script.lua -- -- load modules 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 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 .. '$') end end -- match patterns function _match_patterns(patterns, plat, arch, excluded) for _, pattern in ipairs(patterns) do if _match_pattern(pattern, plat, arch, excluded) then return true end end end -- mattch the script pattern -- -- @note interpreter has converted pattern to a lua pattern ('*' => '.*') -- -- matched pattern: -- plat|arch@subhost|subarch -- -- e.g. -- -- `@linux` -- `@linux|x86_64` -- `@macosx,linux` -- `android@macosx,linux` -- `android|armeabi-v7a@macosx,linux` -- `android|armeabi-v7a,iphoneos@macosx,linux|x86_64` -- `android|armeabi-v7a@linux|x86_64` -- `linux|*` -- -- excluded pattern: -- !plat|!arch@!subhost|!subarch -- -- e.g. -- -- `@!linux` -- `@!linux|x86_64` -- `@!macosx,!linux` -- `!android@macosx,!linux` -- `android|!armeabi-v7a@macosx,!linux` -- `android|armeabi-v7a,!iphoneos@macosx,!linux|x86_64` -- `!android|armeabi-v7a@!linux|!x86_64` -- `!linux|*` -- function _match_script(pattern, plat, arch, excluded) local splitinfo = pattern:split("@", {strict = true, plain = true}) local plat_part = splitinfo[1] local host_part = splitinfo[2] local plat_patterns if plat_part and #plat_part > 0 then plat_patterns = plat_part:split(",", {plain = true}) end local host_patterns if host_part and #host_part > 0 then host_patterns = host_part:split(",", {plain = true}) end if plat_patterns and #plat_patterns > 0 then if _match_patterns(plat_patterns, plat, arch, excluded) then if host_patterns and #host_patterns > 0 and not _match_patterns(host_patterns, os.subhost(), os.subarch(), excluded) 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) end end end -- select the matched pattern script for the current platform/architecture function select_script(scripts, opt) opt = opt or {} local result = nil 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 script_matched = script break end end if not script_matched then local scripts_fallback = {} local patterns_fallback = {} for pattern, script in pairs(scripts) do if not pattern:startswith("__") and _match_script(pattern, plat, arch, true) then table.insert(scripts_fallback, script) table.insert(patterns_fallback, pattern) end end script_matched = scripts_fallback[1] if script_matched and #scripts_fallback > 0 then local conflict_patterns = {patterns_fallback[1]} for idx, script in ipairs(scripts_fallback) do local pattern = patterns_fallback[idx] if script ~= script_matched then table.insert(conflict_patterns, pattern) end end if #conflict_patterns > 1 then utils.warning("multiple script patterns are matched, %s", table.concat(conflict_patterns, ", ")) end end end result = script_matched or scripts["__generic__"] end return result end return select_script