diff options
| -rw-r--r-- | xmake/rules/c++/modules/modules_support/common.lua | 60 |
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 |
