summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur LAURENT <[email protected]>2025-05-16 15:06:02 +0200
committerArthur LAURENT <[email protected]>2025-05-16 15:06:02 +0200
commitafa8d329edd2dda64ed15f29ce1498f7943b32db (patch)
tree942b60b899291df2809da397e0df284d00fcf4b9
parent8fe7c166f84ee0460c79a63f5dc19d4ca77dade1 (diff)
(C++ modules support) fix unitybuild, pch and c++ modules objectfiles conflicts
-rw-r--r--xmake/core/project/target.lua3
-rw-r--r--xmake/rules/c++/modules/builder.lua29
-rw-r--r--xmake/rules/c++/modules/clang/builder.lua9
-rw-r--r--xmake/rules/c++/modules/config.lua28
-rw-r--r--xmake/rules/c++/modules/gcc/builder.lua6
-rw-r--r--xmake/rules/c++/modules/msvc/builder.lua6
-rw-r--r--xmake/rules/c++/modules/scanner.lua120
-rw-r--r--xmake/rules/c++/modules/xmake.lua1
8 files changed, 113 insertions, 89 deletions
diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua
index 475c06d19..6f4ad4d89 100644
--- a/xmake/core/project/target.lua
+++ b/xmake/core/project/target.lua
@@ -2099,7 +2099,6 @@ function _instance:objectfiles()
-- get object files from source batches
local objectfiles = {}
local batchcount = 0
- local sourcebatches = self:sourcebatches()
local orderkeys = table.keys(sourcebatches)
table.sort(orderkeys) -- @note we need to guarantee the order of objectfiles for depend.is_changed() and etc.
for _, k in ipairs(orderkeys) do
@@ -2381,7 +2380,7 @@ function _instance:sourcebatches()
if filerule:extraconf("sourcekinds", sourcekind, "objectfiles") ~= false then
sourcebatch.objectfiles = sourcebatch.objectfiles or {}
sourcebatch.dependfiles = sourcebatch.dependfiles or {}
- local objectfile = self:objectfile(sourcefile, sourcekind)
+ local objectfile = self:objectfile(sourcefile)
table.insert(sourcebatch.objectfiles, objectfile)
table.insert(sourcebatch.dependfiles, self:dependfile(objectfile))
end
diff --git a/xmake/rules/c++/modules/builder.lua b/xmake/rules/c++/modules/builder.lua
index 44da4d622..151c3ed9e 100644
--- a/xmake/rules/c++/modules/builder.lua
+++ b/xmake/rules/c++/modules/builder.lua
@@ -191,11 +191,11 @@ function build_modules_for_jobgraph(target, jobgraph, built_modules)
local jobdeps = {}
local buildfilejobs = {}
- -- if two phase supported only build interface and implementation named modules bmi
+ -- get named modules
local _built_modules = {}
for _, sourcefile in ipairs(built_modules) do
local module = mapper.get(target, sourcefile)
- if module.interface or module.implementation then
+ if module.name then
table.insert(_built_modules, sourcefile)
else
if not support.is_bmionly(target, sourcefile) then
@@ -209,7 +209,6 @@ function build_modules_for_jobgraph(target, jobgraph, built_modules)
end
end
end
-
-- add module jobs
local moduletype = has_two_phase_compilation_support and "bmi" or "onephase"
local buildgroup = _get_module_buildgroup_for(target, moduletype)
@@ -221,7 +220,7 @@ function build_modules_for_jobgraph(target, jobgraph, built_modules)
table.insert(buildfilejobs, buildfilejob)
jobgraph:add(buildfilejob, function(_, _, jobopt)
-- build bmi if named job
- jobopt.bmi = module.interface or module.implementation
+ jobopt.bmi = module.name
-- build objectfile here if two phase compilation is not supported
jobopt.objectfile = not has_two_phase_compilation_support and not bmionly
builder.make_module_job(target, module, jobopt)
@@ -261,7 +260,7 @@ function build_objectfiles_for_jobgraph(target, jobgraph, built_modules)
else
for _, sourcefile in ipairs(built_modules) do
local module = mapper.get(target, sourcefile)
- if not module.interface and not module.implementation then
+ if not module.name then
table.insert(_built_modules, sourcefile)
end
end
@@ -295,11 +294,11 @@ function build_modules_for_batchjobs(target, batchjobs, built_modules, opt)
local builder = _builder(target)
local has_two_phase_compilation_support = support.has_two_phase_compilation_support(target)
- -- if two phase supported only build interface and implementation named modules bmi
+ -- if two phase supported only build named modules bmi
local _built_modules = {}
for _, sourcefile in ipairs(built_modules) do
local module = mapper.get(target, sourcefile)
- if module.interface or module.implementation then
+ if module.name then
table.insert(_built_modules, sourcefile)
end
end
@@ -339,7 +338,7 @@ function build_modules_for_batchjobs(target, batchjobs, built_modules, opt)
sourcefile = module.sourcefile,
job = batchjobs:newjob(buildfilejob, function(_, _, jobopt)
-- build bmi if named job
- jobopt.bmi = module.interface or module.implementation
+ jobopt.bmi = module.name
-- build objectfile here if two phase compilation is not supported
jobopt.objectfile = not has_two_phase_compilation_support and not bmionly
builder.make_module_job(target, module, jobopt)
@@ -362,7 +361,7 @@ function build_objectfiles_for_batchjobs(target, batchjobs, built_modules, opt)
else
for _, sourcefile in ipairs(built_modules) do
local module = mapper.get(target, sourcefile)
- if not module.interface and not module.implementation then
+ if not module.name then
table.insert(_built_modules, sourcefile)
end
end
@@ -399,7 +398,7 @@ function build_modules_for_batchcmds(target, batchcmds, built_modules, opt)
local _built_modules = {}
for _, sourcefile in ipairs(built_modules) do
local module = mapper.get(target, sourcefile)
- if module.interface or module.implementation then
+ if module.name then
table.insert(_built_modules, sourcefile)
end
end
@@ -408,7 +407,7 @@ function build_modules_for_batchcmds(target, batchcmds, built_modules, opt)
local bmionly = support.is_bmionly(target, sourcefile)
local module = mapper.get(target, sourcefile)
local jobopt = {}
- jobopt.bmi = module.interface or module.implementation
+ jobopt.bmi = module.name
jobopt.objectfile = not has_two_phase_compilation_support and not bmionly
jobopt.progress = opt.progress
depmtime = math.max(depmtime, builder.make_module_buildcmds(target, batchcmds, module, jobopt))
@@ -429,8 +428,8 @@ function build_objectfiles_for_batchcmds(target, batchcmds, built_modules, opt)
else
for _, sourcefile in ipairs(built_modules) do
local module = mapper.get(target, sourcefile)
- if not module.interface and not module.implementation then
- table.insert(_built_modules, sourcefile)
+ if not module.name then
+ table.insert(_built_modules, sourcefile)
end
end
end
@@ -641,7 +640,7 @@ end
function build_bmis(target, jobgraph, _, opt)
opt = opt or {}
if target:data("cxx.has_modules") then
- if target:is_moduleonly() and not target:data("cxx.modules.reused") then
+ if target:is_moduleonly() and not target:data("cxx.modules.reused") or target:is_phony() then
return
end
local modules = scanner.get_modules(target)
@@ -686,7 +685,7 @@ end
function build_objectfiles(target, jobgraph, _, opt)
if target:data("cxx.has_modules") then
- if target:is_moduleonly() and not target:data("cxx.modules.reused") then
+ if target:is_moduleonly() and not target:data("cxx.modules.reused") or target:is_phony() then
return
end
local modules = scanner.get_modules(target)
diff --git a/xmake/rules/c++/modules/clang/builder.lua b/xmake/rules/c++/modules/clang/builder.lua
index 474793472..797167283 100644
--- a/xmake/rules/c++/modules/clang/builder.lua
+++ b/xmake/rules/c++/modules/clang/builder.lua
@@ -218,11 +218,6 @@ function make_module_job(target, module, opt)
local dryrun = option.get("dry-run")
- -- append requires flags
- -- if module.deps then
- -- _append_requires_flags(target, module)
- -- end
-
local build = should_build(target, module)
local bmi = opt and opt.bmi
local objectfile = opt and opt.objectfile
@@ -246,7 +241,7 @@ function make_module_job(target, module, opt)
elseif bmi then
_compile_bmi_step(target, module, opt)
else
- if support.has_module_extension(module.sourcefile) or module.interface or module.implementation then
+ if support.has_module_extension(module.sourcefile) or module.name then
_compile_objectfile_step(target, module, opt)
else
os.tryrm(module.objectfile) -- force rebuild for .cpp files
@@ -277,7 +272,7 @@ function make_module_buildcmds(target, batchcmds, module, opt)
elseif bmi then
_compile_bmi_step(target, module, table.join(opt, {batchcmds = batchcmds}))
else
- if support.has_module_extension(module.sourcefile) or module.interface or module.implementation then
+ if support.has_module_extension(module.sourcefile) or module.name then
_compile_objectfile_step(target, module, table.join(opt, {batchcmds = batchcmds}))
else
batchcmds:rm(module.objectfile) -- force rebuild for .cpp files
diff --git a/xmake/rules/c++/modules/config.lua b/xmake/rules/c++/modules/config.lua
index 9daa1bfd0..589413532 100644
--- a/xmake/rules/c++/modules/config.lua
+++ b/xmake/rules/c++/modules/config.lua
@@ -67,10 +67,20 @@ function main(target)
wprint("build.c++.modules.tryreuse.discriminate_on_defines is deprecated, please use build.c++.modules.reuse.strict")
end
+ -- if containes modules, enable objectfiles output of c++.build.modules.builder
+ local rule = target:rule("c++.build.modules.builder")
+ rule = rule:clone()
+ if rule then
+ rule:extraconf_set("sourcekinds", "cxx", "objectfiles", true)
+ target:rule_add(rule)
+ target:add("files")
+ end
+
-- moduleonly modules are implicitly public
if target:is_moduleonly() then
- local sourcebatch = target:sourcebatches()["c++.build.modules.builder"]
- if sourcebatch then
+ local sourcebatches = target:sourcebatches()
+ if sourcebatches and sourcebatches["c++.build.modules.scanner"] then
+ local sourcebatch = sourcebatches["c++.build.modules.scanner"]
for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
target:fileconfig_add(sourcefile, {public = true})
end
@@ -81,11 +91,15 @@ end
function insert_stdmodules(target)
if target:data("cxx.has_modules") then
- -- add std modules to sourcebatch
- local stdmodules = support.get_stdmodules(target)
- for _, sourcefile in ipairs(stdmodules) do
- table.insert(target:sourcebatches()["c++.build.modules.scanner"].sourcefiles, sourcefile)
- table.insert(target:sourcebatches()["c++.build.modules.builder"].sourcefiles, sourcefile)
+ local sourcebatches = target:sourcebatches()
+ if sourcebatches and sourcebatches["c++.build.modules.scanner"] then
+ local sourcebatch = sourcebatches["c++.build.modules.scanner"]
+ sourcebatch.sourcefiles = sourcebatch.sourcefiles or {}
+ -- add std modules to sourcebatch
+ local stdmodules = support.get_stdmodules(target)
+ for _, sourcefile in ipairs(stdmodules) do
+ table.insert(sourcebatch.sourcefiles, sourcefile)
+ end
end
end
end
diff --git a/xmake/rules/c++/modules/gcc/builder.lua b/xmake/rules/c++/modules/gcc/builder.lua
index 7e207f396..54b47d41c 100644
--- a/xmake/rules/c++/modules/gcc/builder.lua
+++ b/xmake/rules/c++/modules/gcc/builder.lua
@@ -129,7 +129,7 @@ end
function _get_maplines(target, module)
local maplines = {}
- if module.interface or module.implementation then
+ if module.name then
table.insert(maplines, module.name .. " " .. path.absolute(module.bmifile))
end
for dep_name, dep_module in table.orderpairs(module.deps) do
@@ -223,7 +223,7 @@ function make_module_job(target, module, opt)
end
local flags = {"-x", "c++"}
- if support.has_module_extension(module.sourcefile) or module.interface or module.implementation then
+ if support.has_module_extension(module.sourcefile) or module.name then
if bmi then
if objectfile then
table.insert(flags, module_flag)
@@ -270,7 +270,7 @@ function make_module_buildcmds(target, batchcmds, module, opt)
end
local flags = {"-x", "c++"}
- if support.has_module_extension(module.sourcefile) or module.interface or module.implementation then
+ if support.has_module_extension(module.sourcefile) or module.name then
if bmi then
if objectfile then
table.insert(flags, module_flag)
diff --git a/xmake/rules/c++/modules/msvc/builder.lua b/xmake/rules/c++/modules/msvc/builder.lua
index fa9c7021c..0fb17244b 100644
--- a/xmake/rules/c++/modules/msvc/builder.lua
+++ b/xmake/rules/c++/modules/msvc/builder.lua
@@ -43,7 +43,7 @@ function _make_modulebuildflags(target, module, opt)
local bmionly = opt.bmi and not opt.objectfile
local flags
- if module.interface or module.implementation then -- named module
+ if module.name then -- named module
flags = table.join("-TP", module.interface and interfaceflag or internalpartitionflag, bmionly and ifconlyflag or {}, ifcoutputflag, path(module.bmifile))
else
flags = {"-TP"}
@@ -258,7 +258,7 @@ function make_module_job(target, module, opt)
elseif bmi then
_compile_bmi_step(target, module, opt)
else
- if support.has_module_extension(module.sourcefile) or module.interface or module.implementation then
+ if support.has_module_extension(module.sourcefile) or module.name then
_compile_objectfile_step(target, module, opt)
else
os.tryrm(module.objectfile) -- force rebuild for .cpp files
@@ -287,7 +287,7 @@ function make_module_buildcmds(target, batchcmds, module, opt)
elseif bmi then
_compile_bmi_step(target, module, table.join(opt, {batchcmds = batchcmds}))
else
- if support.has_module_extension(module.sourcefile) or module.interface or module.implementation then
+ if support.has_module_extension(module.sourcefile) or module.name then
_compile_objectfile_step(target, module, table.join(opt, {batchcmds = batchcmds}))
else
batchcmds:rm(module.objectfile) -- force rebuild for .cpp files
diff --git a/xmake/rules/c++/modules/scanner.lua b/xmake/rules/c++/modules/scanner.lua
index fe9b9c63d..9c71fa035 100644
--- a/xmake/rules/c++/modules/scanner.lua
+++ b/xmake/rules/c++/modules/scanner.lua
@@ -145,8 +145,9 @@ function _parse_dependencies_data(target, moduleinfos)
modules_names:insert(module.name)
module.headerunit = provide["is-headerunit"]
module.interface = (not module.headerunit and provide["is-interface"] == nil) and true or provide["is-interface"]
- module.implementation = not module.interface and not module.headerunit
- module.method = provide["lookup-method"] or "by-name"
+ if module.name then
+ module.method = provide["lookup-method"] or "by-name"
+ end
if module.headerunit then
local key = support.get_headerunit_key(target, module.sourcefile)
@@ -199,7 +200,7 @@ function _get_edges(target, nodes, modules)
local deps_names = hashset.new()
for _, node in ipairs(table.unique(nodes)) do
local module = modules[node]
- if module.interface or module.implementation then
+ if module.name then
if deps_names:has(module.name) then
raise("duplicate module name detected for \"" .. module.name .. "\"\n <" .. target:fullname() .. "> -> " .. module.sourcefile .. "\n <" .. target:fullname() .. "> -> " .. name_filemap[module.name])
end
@@ -212,7 +213,7 @@ function _get_edges(target, nodes, modules)
for dep_name, _ in table.orderpairs(module.deps) do
for _, dep_node in ipairs(nodes) do
local dep_module = modules[dep_node]
- if (dep_module.interface or dep_module.implementation or dep_module.headerunit) and dep_name == dep_module.name then
+ if dep_module.name and dep_name == dep_module.name then
table.insert(edges, {dep_node, node})
break
end
@@ -280,31 +281,34 @@ function _get_targetdeps_modules(target)
local _, stdmodules_set = support.get_stdmodules(target)
local modules
for _, dep in ipairs(target:orderdeps()) do
- local sourcebatch = dep:sourcebatches()["c++.build.modules.builder"]
- if sourcebatch and sourcebatch.sourcefiles then
- for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
- modules = modules or {}
- if support.is_public(dep, sourcefile) or stdmodules_set:has(sourcefile) then
- local _fileconfig = dep:fileconfig(sourcefile)
- local fileconfig = {}
- if _fileconfig then
- fileconfig.defines = _fileconfig.defines
- fileconfig.undefines = _fileconfig.undefines
- fileconfig.includedirs = _fileconfig.includedirs
- end
- fileconfig.defines = table.join(fileconfig.defines or {}, dep:get("defines") or {})
- fileconfig.undefines = table.join(fileconfig.undefines or {}, dep:get("undefines") or {})
- fileconfig.includedirs = table.join(fileconfig.includedirs or {}, dep:get("includedirs") or {})
- if not dep:is_phony() then
- if target:namespace() == dep:namespace() then
- fileconfig.external = dep:name()
- else
- fileconfig.external = dep:fullname()
+ local sourcebatches = dep:sourcebatches()
+ if sourcebatches and sourcebatches["c++.build.modules.scanner"] then
+ local sourcebatch = sourcebatches["c++.build.modules.scanner"]
+ if sourcebatch.sourcefiles then
+ for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
+ modules = modules or {}
+ if support.is_public(dep, sourcefile) or stdmodules_set:has(sourcefile) then
+ local _fileconfig = dep:fileconfig(sourcefile)
+ local fileconfig = {}
+ if _fileconfig then
+ fileconfig.defines = _fileconfig.defines
+ fileconfig.undefines = _fileconfig.undefines
+ fileconfig.includedirs = _fileconfig.includedirs
+ end
+ fileconfig.defines = table.join(fileconfig.defines or {}, dep:get("defines") or {})
+ fileconfig.undefines = table.join(fileconfig.undefines or {}, dep:get("undefines") or {})
+ fileconfig.includedirs = table.join(fileconfig.includedirs or {}, dep:get("includedirs") or {})
+ if not dep:is_phony() then
+ if target:namespace() == dep:namespace() then
+ fileconfig.external = dep:name()
+ else
+ fileconfig.external = dep:fullname()
+ end
+ fileconfig.bmionly = not dep:is_moduleonly()
+ end
+ if not modules[sourcefile] then
+ modules[sourcefile] = fileconfig
end
- fileconfig.bmionly = not dep:is_moduleonly()
- end
- if not modules[sourcefile] then
- modules[sourcefile] = fileconfig
end
end
end
@@ -377,13 +381,12 @@ function _patch_sourcebatch(target, sourcebatch)
end
sourcebatch.sourcekind = "cxx"
- sourcebatch.objectfiles = {}
sourcebatch.dependfiles = {}
for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
local reused, from = support.is_reused(target, sourcefile)
local _target = reused and from or target
local objectfile = _target:objectfile(sourcefile)
- local dependfile = _target:dependfile(sourcefile or objectfile)
+ local dependfile = _target:dependfile(objectfile)
table.insert(sourcebatch.dependfiles, dependfile)
end
end
@@ -420,16 +423,24 @@ function _do_parse(target, sourcebatch)
end
-- steal from c++.build sourcebatch named modules with cpp extensions
- local cxx_sourcebatch = target:sourcebatches()["c++.build"]
- if cxx_sourcebatch then
+ local sourcebatches = target:sourcebatches()
+ if sourcebatches and sourcebatches["c++.build"] then
+ local cxx_sourcebatch = sourcebatches["c++.build"]
cxx_sourcebatch.sourcefiles = {}
cxx_sourcebatch.dependfiles = {}
+ cxx_sourcebatch.objectfiles = {}
for _, sourcefile in ipairs(sourcebatch.sourcefiles) do
local module = mapper.get(target, sourcefile)
- if module and not module.interface and not module.implementation then
+ local insert = true
+ if module then
+ insert = not module.name
+ end
+
+ if insert then
table.insert(cxx_sourcebatch.sourcefiles, sourcefile)
local objectfile = target:objectfile(sourcefile)
table.insert(cxx_sourcebatch.dependfiles, target:dependfile(objectfile))
+ table.insert(cxx_sourcebatch.objectfiles, objectfile)
end
end
end
@@ -688,16 +699,14 @@ function sort_modules_by_dependencies(target, modules)
local culleds
for _, sourcefile in ipairs(sourcefiles_sorted) do
local module = mapper.get(target, sourcefile)
- local is_named = module.interface or module.implementation or module.headerunit
- local sort = (is_named and module.sourcealias) or (module.headerunit and not module.alias) or (not is_named)
+ local name = module.name
+ local is_named = name ~= nil
+ local sort = (is_named and (module.sourcealias or not module.alias)) or not is_named
if sort then
local insert = false
- local name
local reused, from = support.is_reused(target, sourcefile)
- if module.name and not module.headerunit then -- named modules
- name = module.name
-
+ if is_named and not module.headerunit then -- named modules
insert = not support.can_be_culled(target, sourcefile)
-- if module is cullable (culling policy enabled and not a public module), try to cull
@@ -726,9 +735,9 @@ function sort_modules_by_dependencies(target, modules)
table.insert(built_headerunits, sourcefile)
else
table.insert(built_modules, sourcefile)
- -- insert objectfile if module is not imported from a static / shared library and if has a custom extension (not .cpp)
+ -- insert objectfile if module named and is not imported from a static / shared library or if from a C++ file with a c++ module extension
-- if not so objectfile will be handled by c++.build rule
- if not support.is_bmionly(target, sourcefile) then
+ if not support.is_bmionly(target, sourcefile) and (support.has_module_extension(sourcefile) or is_named) then
local objectfile = target:objectfile(sourcefile)
table.insert(objectfiles, tostring(objectfile))
end
@@ -775,19 +784,28 @@ function get_modules(target)
end
function after_scan(target)
- local compile_commands = os.getenv("XMAKE_IN_PROJECT_GENERATOR") and os.getenv("XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR")
- if not os.getenv("XMAKE_IN_PROJECT_GENERATOR") or compile_commands then
- local sourcebatch_scanner = target:sourcebatches()["c++.build.modules.scanner"]
- local sourcebatch_builder = target:sourcebatches()["c++.build.modules.builder"]
- if target:data("cxx.has_modules") and not target:is_moduleonly() then
+ local sourcebatches = target:sourcebatches()
+ local sourcebatch_builder = sourcebatches and sourcebatches["c++.build.modules.builder"]
+ local sourcebatch_scanner = sourcebatches and sourcebatches["c++.build.modules.scanner"]
+ if sourcebatch_scanner then
+ sourcebatch_scanner.sourcefiles = {}
+ end
+ if sourcebatch_builder then
+ sourcebatch_builder.sourcefiles = {}
+ sourcebatch_builder.dependfiles = {}
+ sourcebatch_builder.objectfiles = {}
+ end
+ if target:data("cxx.has_modules") then
+ if target:is_moduleonly() or target:is_phony() then
+ return
+ end
+ local compile_commands = os.getenv("XMAKE_IN_PROJECT_GENERATOR") and os.getenv("XMAKE_IN_COMPILE_COMMANDS_PROJECT_GENERATOR")
+ local need_objectfiles = not os.getenv("XMAKE_IN_PROJECT_GENERATOR") or compile_commands
+ if need_objectfiles then
local modules = get_modules(target)
local _, _, objectfiles = sort_modules_by_dependencies(target, modules, {jobgraph = target:policy("build.jobgraph")})
- sourcebatch_scanner.objectfiles = objectfiles
+ assert(sourcebatch_builder)
sourcebatch_builder.objectfiles = objectfiles
- elseif sourcebatch_scanner then
- -- avoid duplicate linking of object files of non-module programs
- sourcebatch_scanner.objectfiles = {}
- sourcebatch_builder.objectfiles = {}
end
end
end
diff --git a/xmake/rules/c++/modules/xmake.lua b/xmake/rules/c++/modules/xmake.lua
index 9afd4f6cc..8633c544c 100644
--- a/xmake/rules/c++/modules/xmake.lua
+++ b/xmake/rules/c++/modules/xmake.lua
@@ -58,6 +58,5 @@ rule("c++.build.modules.builder")
-- install modules
rule("c++.build.modules.install")
set_extensions(".cppm", ".ccm", ".cxxm", ".c++m", ".mpp", ".mxx", ".ixx")
-
before_install("install.install")
before_uninstall("install.uninstall")