summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur LAURENT <[email protected]>2024-07-24 02:29:45 +0200
committerArthur LAURENT <[email protected]>2024-07-24 02:29:45 +0200
commite2fb5383a099652e2ac29b139a60e3d723d66113 (patch)
tree3c9bce246eeccddbe2029e639db4af0567813220
parentdf5cb9cce6cbb757c12f07677edf27b4be219f48 (diff)
fix objectfiles culling
-rw-r--r--xmake/rules/c++/modules/modules_support/dependency_scanner.lua71
-rw-r--r--xmake/rules/c++/modules/xmake.lua10
2 files changed, 56 insertions, 25 deletions
diff --git a/xmake/rules/c++/modules/modules_support/dependency_scanner.lua b/xmake/rules/c++/modules/modules_support/dependency_scanner.lua
index fe544ee77..f4ac77712 100644
--- a/xmake/rules/c++/modules/modules_support/dependency_scanner.lua
+++ b/xmake/rules/c++/modules/modules_support/dependency_scanner.lua
@@ -176,13 +176,17 @@ end
function _get_edges(nodes, modules)
local edges = {}
local module_names = {}
+ local name_filemap = {}
local named_module_names = hashset.new()
- for _, node in ipairs(nodes) do
+ for _, node in ipairs(table.unique(nodes)) do
local module = modules[node]
- local module_name, _, _ = compiler_support.get_provided_module(module)
+ local module_name, _, cppfile = compiler_support.get_provided_module(module)
if module_name then
- assert(not named_module_names:has(module_name), "duplicate module name detected \"" .. module_name .. "\"")
+ if named_module_names:has(module_name) then
+ raise("duplicate module name detected \"" .. module_name .. "\"\n -> " .. cppfile .. "\n -> " .. name_filemap[module_name])
+ end
named_module_names:insert(module_name)
+ name_filemap[module_name] = cppfile
end
if module.requires then
for required_name, _ in table.orderpairs(module.requires) do
@@ -403,8 +407,9 @@ function get_all_packages_modules(target, opt)
end
-- topological sort
-function sort_modules_by_dependencies(target, objectfiles, modules)
- local result = {}
+function sort_modules_by_dependencies(target, objectfiles, modules, opt)
+ local build_objectfiles = {}
+ local link_objectfiles = {}
local edges = _get_edges(objectfiles, modules)
local dag = graph.new(true)
for _, e in ipairs(edges) do
@@ -421,33 +426,53 @@ function sort_modules_by_dependencies(target, objectfiles, modules)
table.insert(names, name or cppfile)
raise("circular modules dependency detected!\n%s", table.concat(names, "\n -> import "))
end
- local objectfiles_sorted = dag:topological_sort()
- for _, objectfile in ipairs(objectfiles_sorted) do
- table.insert(result, objectfile)
- end
+ local objectfiles_sorted = table.reverse(dag:topological_sort())
local objectfiles_sorted_set = hashset.from(objectfiles_sorted)
for _, objectfile in ipairs(objectfiles) do
if not objectfiles_sorted_set:has(objectfile) then
- if target:policy("build.c++.modules.culling") then
- -- cull unreferenced non-public named module but add non-module files and implementation modules
- local _, provide, cppfile = compiler_support.get_provided_module(modules[objectfile])
- local fileconfig = target:fileconfig(cppfile)
+ table.insert(objectfiles_sorted, objectfile)
+ objectfiles_sorted_set:insert(objectfile)
+ end
+ end
+ for _, objectfile in ipairs(objectfiles_sorted) do
+ local name, provide, cppfile = compiler_support.get_provided_module(modules[objectfile])
+ local fileconfig = target:fileconfig(cppfile)
+ local public = fileconfig and fileconfig.public
+ local external = fileconfig and fileconfig.external
+ local can_cull = (fileconfig and fileconfig.cull ~= nil) and fileconfig.cull or true
+ can_cull = can_cull and target:policy("build.c++.modules.culling")
+ local insert = true
+ if provide then
+ insert = public or (not external or external.moduleonly)
+ if insert and not public and can_cull then
+ insert = false
+ local edges = dag:adjacent_edges(objectfile)
local public = fileconfig and fileconfig.public
- local external = fileconfig and fileconfig.external
- local moduleonly = external and external.moduleonly
- local dont_cull = fileconfig and fileconfig.cull ~= nil and not fileconfig.cull
- if not provide or public or moduleonly or dont_cull then
- table.insert(result, objectfile)
- else
- wprint("%s has been culled because it's not consumed by its target (%s) nor flagged as a public module (add_files(\"xxx.cppm\", {public = true}))", cppfile, target:name())
+ if edges then
+ for _, edge in ipairs(edges) do
+ if edge:to() ~= objectfile and objectfiles_sorted_set:has(edge:to()) then
+ insert = true
+ break
+ end
+ end
end
- else
- table.insert(result, objectfile)
+ end
+ end
+ if insert then
+ table.insert(build_objectfiles, objectfile)
+ table.insert(link_objectfiles, objectfile)
+ elseif external and not external.from_moduleonly then
+ table.insert(build_objectfiles, objectfile)
+ else
+ objectfiles_sorted_set:remove(objectfile)
+ if name ~= "std" and name ~= "std.compat" then
+ wprint("%s has been culled because it's not consumed by its target (%s) nor flagged as a public module (add_files(\"%s\", {public = true}))", name, target:name(), path.filename(cppfile))
end
end
end
- return result
+
+ return build_objectfiles, link_objectfiles
end
-- get source modulefile for external target deps
diff --git a/xmake/rules/c++/modules/xmake.lua b/xmake/rules/c++/modules/xmake.lua
index 67a4a1497..7fa967b01 100644
--- a/xmake/rules/c++/modules/xmake.lua
+++ b/xmake/rules/c++/modules/xmake.lua
@@ -107,13 +107,16 @@ rule("c++.build.modules.builder")
if not target:is_moduleonly() then
-- avoid building non referenced modules
- sourcebatch.objectfiles = dependency_scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules)
+ local build_objectfiles, link_objectfiles = dependency_scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules)
+ sourcebatch.objectfiles = build_objectfiles
-- build modules
builder.build_modules_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
-- build headerunits and we need to do it before building modules
builder.build_headerunits_for_batchjobs(target, batchjobs, sourcebatch, modules, opt)
+
+ sourcebatch.objectfiles = link_objectfiles
else
sourcebatch.objectfiles = {}
end
@@ -165,13 +168,16 @@ rule("c++.build.modules.builder")
if not target:is_moduleonly() then
-- avoid building non referenced modules
- sourcebatch.objectfiles = dependency_scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules)
+ local build_objectfiles, link_objectfiles = dependency_scanner.sort_modules_by_dependencies(target, sourcebatch.objectfiles, modules)
+ sourcebatch.objectfiles = build_objectfiles
-- build headerunits
builder.build_headerunits_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
-- build modules
builder.build_modules_for_batchcmds(target, batchcmds, sourcebatch, modules, opt)
+
+ sourcebatch.objectfiles = link_objectfiles
else
-- avoid duplicate linking of object files of non-module programs
sourcebatch.objectfiles = {}