--!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, Xmake Open Source Community. -- -- @author ruki -- @file instance_deps.lua -- -- define module local instance_deps = instance_deps or {} -- load modules local option = require("base/option") local string = require("base/string") local table = require("base/table") -- load deps for instance: e.g. option, instance and rule -- -- e.g. -- -- a.deps = b -- b.deps = c -- foo.deps = a d -- -- foo.orderdeps: d -> c -> b -> a -- -- if they're targets, their links order is reverse(orderdeps), e.g. foo: a -> b -> c -> d -- function instance_deps.load_deps(instance, instances, deps, orderdeps, depspath, walkdep) local plaindeps = table.wrap(instance:get("deps")) local total = #plaindeps for idx, _ in ipairs(plaindeps) do -- we reverse to get the flat dependencies in order to ensure the correct linking order -- @see https://github.com/xmake-io/xmake/issues/3144 local depname = plaindeps[total + 1 - idx] local depinst = instances[depname] if depinst == nil and instance.namespace then local namespace = instance:namespace() if namespace then depinst = instances[namespace .. "::" .. depname] end end if depinst then local continue_walk = true if walkdep then continue_walk = walkdep(instance, depinst) end if continue_walk then if not deps[depname] then deps[depname] = depinst local depspath_sub if depspath then for idx, name in ipairs(depspath) do if name == depname then local circular_deps = table.slice(depspath, idx) table.insert(circular_deps, depname) os.raise("circular dependency(%s) detected!", table.concat(circular_deps, ", ")) end end depspath_sub = table.join(depspath, depname) end instance_deps.load_deps(depinst, instances, deps, orderdeps, depspath_sub, walkdep) table.insert(orderdeps, depinst) end end end end end -- sort the given instance with deps function instance_deps._sort_instance(instance, instances, orderinstances, instancerefs, depspath) if not instancerefs[instance:fullname()] then instancerefs[instance:fullname()] = true for _, depname in ipairs(table.wrap(instance:get("deps"))) do local depinst = instances[depname] if depinst == nil and instance.namespace then local namespace = instance:namespace() if namespace then depinst = instances[namespace .. "::" .. depname] end end if depinst then local depspath_sub if depspath then for idx, name in ipairs(depspath) do if name == depname then local circular_deps = table.slice(depspath, idx) table.insert(circular_deps, depname) os.raise("circular dependency(%s) detected!", table.concat(circular_deps, ", ")) end end depspath_sub = table.join(depspath, depinst:fullname()) end instance_deps._sort_instance(depinst, instances, orderinstances, instancerefs, depspath_sub) end end table.insert(orderinstances, instance) end end -- sort instances with deps -- -- e.g. -- -- a.deps = b -- b.deps = c -- foo.deps = a d -- -- orderdeps: c -> b -> a -> d -> foo function instance_deps.sort(instances) local refs = {} local orderinstances = {} for _, instance in table.orderpairs(instances) do instance_deps._sort_instance(instance, instances, orderinstances, refs, {instance:fullname()}) end return orderinstances end -- return module return instance_deps