summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xmake/rules/c++/modules/modules_support/common.lua60
1 files changed, 58 insertions, 2 deletions
diff --git a/xmake/rules/c++/modules/modules_support/common.lua b/xmake/rules/c++/modules/modules_support/common.lua
index b77411155..175a0db8c 100644
--- a/xmake/rules/c++/modules/modules_support/common.lua
+++ b/xmake/rules/c++/modules/modules_support/common.lua
@@ -203,7 +203,7 @@ end
}
}
}]]
-function parse_dependency_data(target, moduleinfos)
+function _parse_dependencies_data(target, moduleinfos)
local modules
local cachedir = modules_cachedir(target)
for _, moduleinfo in ipairs(moduleinfos) do
@@ -266,6 +266,59 @@ function parse_dependency_data(target, moduleinfos)
return modules
end
+-- check circular dependencies for the given module
+function _check_circular_dependencies_of_module(name, moduledeps, modulesources, depspath)
+ for _, dep in ipairs(moduledeps[name]) do
+ local depinfo = moduledeps[dep]
+ if depinfo then
+ local depspath_sub
+ if depspath then
+ for idx, name in ipairs(depspath) do
+ if name == dep then
+ local circular_deps = table.slice(depspath, idx)
+ table.insert(circular_deps, dep)
+ local sourceinfo = ""
+ for _, circular_depname in ipairs(circular_deps) do
+ local sourcefile = modulesources[circular_depname]
+ if sourcefile then
+ sourceinfo = sourceinfo .. ("\n -> module(%s) in %s"):format(circular_depname, sourcefile)
+ end
+ end
+ os.raise("circular modules dependency(%s) detected!%s", table.concat(circular_deps, ", "), sourceinfo)
+ end
+ end
+ depspath_sub = table.join(depspath, dep)
+ end
+ _check_circular_dependencies_of_module(dep, moduledeps, modulesources, depspath_sub)
+ end
+ end
+end
+
+-- check circular dependencies
+-- @see https://github.com/xmake-io/xmake/issues/3031
+function _check_circular_dependencies(modules)
+ local moduledeps = {}
+ local modulesources = {}
+ for _, mod in pairs(modules) do
+ if mod then
+ if mod.provides and mod.requires then
+ for name, provide in pairs(mod.provides) do
+ modulesources[name] = provide.sourcefile
+ local deps = moduledeps[name]
+ if deps then
+ table.join2(deps, mod.requires)
+ else
+ moduledeps[name] = table.keys(mod.requires)
+ end
+ end
+ end
+ end
+ end
+ for name, _ in pairs(moduledeps) do
+ _check_circular_dependencies_of_module(name, moduledeps, modulesources, {name})
+ end
+end
+
function _topological_sort_visit(node, nodes, modules, output)
if node.marked then
return
@@ -455,7 +508,10 @@ function get_module_dependencies(target, sourcebatch, opt)
local changed = modules_support(target).generate_dependencies(target, sourcebatch, opt)
if changed or modules == nil then
local moduleinfos = load_moduleinfos(target, sourcebatch)
- modules = parse_dependency_data(target, moduleinfos)
+ modules = _parse_dependencies_data(target, moduleinfos)
+ if modules then
+ _check_circular_dependencies(modules)
+ end
localcache():set2("modules", cachekey, modules)
localcache():save()
end