From 535fda2702d2e894ac8182c4dba264ee2875e898 Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 8 Nov 2022 00:32:36 +0800 Subject: check module circular deps --- xmake/rules/c++/modules/modules_support/common.lua | 50 +++++++++++++++++++++- 1 file changed, 48 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..377af7222 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,49 @@ function parse_dependency_data(target, moduleinfos) return modules end +-- check circular dependencies for the given module +function _check_circular_dependencies_of_module(name, moduledeps, 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) + os.raise("circular modules dependency(%s) detected!", table.concat(circular_deps, ", ")) + end + end + depspath_sub = table.join(depspath, dep) + end + _check_circular_dependencies_of_module(dep, moduledeps, depspath_sub) + end + end +end + +-- check circular dependencies +function _check_circular_dependencies(modules) + local moduledeps = {} + for _, mod in pairs(modules) do + if mod then + if mod.provides and mod.requires then + for name, _ in pairs(mod.provides) do + 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, {name}) + end +end + function _topological_sort_visit(node, nodes, modules, output) if node.marked then return @@ -455,7 +498,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 -- cgit v1.3.1 From cc35693a3d6812f46d6486c0e16d49c3088b8947 Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 8 Nov 2022 00:32:57 +0800 Subject: improve comments --- xmake/rules/c++/modules/modules_support/common.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/xmake/rules/c++/modules/modules_support/common.lua b/xmake/rules/c++/modules/modules_support/common.lua index 377af7222..c44394d2e 100644 --- a/xmake/rules/c++/modules/modules_support/common.lua +++ b/xmake/rules/c++/modules/modules_support/common.lua @@ -288,6 +288,7 @@ function _check_circular_dependencies_of_module(name, moduledeps, depspath) end -- check circular dependencies +-- @see https://github.com/xmake-io/xmake/issues/3031 function _check_circular_dependencies(modules) local moduledeps = {} for _, mod in pairs(modules) do -- cgit v1.3.1 From 2a95c7a1e0479863de9b89d2a2447b258a378f45 Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 8 Nov 2022 00:34:27 +0800 Subject: improve error tips --- xmake/rules/c++/modules/modules_support/common.lua | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/xmake/rules/c++/modules/modules_support/common.lua b/xmake/rules/c++/modules/modules_support/common.lua index c44394d2e..175a0db8c 100644 --- a/xmake/rules/c++/modules/modules_support/common.lua +++ b/xmake/rules/c++/modules/modules_support/common.lua @@ -267,7 +267,7 @@ function _parse_dependencies_data(target, moduleinfos) end -- check circular dependencies for the given module -function _check_circular_dependencies_of_module(name, moduledeps, depspath) +function _check_circular_dependencies_of_module(name, moduledeps, modulesources, depspath) for _, dep in ipairs(moduledeps[name]) do local depinfo = moduledeps[dep] if depinfo then @@ -277,12 +277,19 @@ function _check_circular_dependencies_of_module(name, moduledeps, depspath) if name == dep then local circular_deps = table.slice(depspath, idx) table.insert(circular_deps, dep) - os.raise("circular modules dependency(%s) detected!", table.concat(circular_deps, ", ")) + 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, depspath_sub) + _check_circular_dependencies_of_module(dep, moduledeps, modulesources, depspath_sub) end end end @@ -291,10 +298,12 @@ end -- @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, _ in pairs(mod.provides) do + for name, provide in pairs(mod.provides) do + modulesources[name] = provide.sourcefile local deps = moduledeps[name] if deps then table.join2(deps, mod.requires) @@ -306,7 +315,7 @@ function _check_circular_dependencies(modules) end end for name, _ in pairs(moduledeps) do - _check_circular_dependencies_of_module(name, moduledeps, {name}) + _check_circular_dependencies_of_module(name, moduledeps, modulesources, {name}) end end -- cgit v1.3.1